2009/12/11 Bryan R Harris <bryan_r_har...@raytheon.com>:
>>> Seems like a waste to do step 2 in a subroutine since we only do it once,
>>> but it does fill the main body of the script with code-noise that makes it
>>> harder to debug overall logic problems...  Not much logic here, but
>>> certainly in more complex scripts.
>>
>> A waste of what exactly? You don't have a limited budget of "sub" keywords.
>
> I guess I figured you had to build in structure (variables?) to be able to
> pass things back and forth from subroutines that normally you wouldn't have
> to set up.
>
> For example, if I'm populating a complex variable @d with lots of pointers,
> hashes, arrays, etc. within, if I populate that within a subroutine, how do
> I get it back out conveniently without it making a whole nother copy of it
> outside?  If it's 500 MB, isn't that horribly inefficient?  Plus, I have to
> keep track of it.

Perl doesn't have pointers; it has references. They are similar but
not the same. Anyway populate_x looks like this:

sub populate_x {
  return [
    # Big complex data structure
    # ...
    # ...
    # ...
    # ...
  ];
}

There is no large scale copying; the [] construct creates a new array
and returns a reference to it. You just return a single scalar value
from the function to the calling context. Kind of like C

int *populate_x (void) {
    int *foo = malloc(X_SIZE * sizeof *foo);
    if (!foo) return NULL;
    /* Do something to populate *foo */
    return foo;
}

but in C this is dangerous and hairy because you're mucking around
with pointers and raw blocks of memory while in Perl you're dealing
just with builtin datatypes.

If you want to populate an array instead:

my @z = populate_z();

# ...and later...

sub populate_z {
  return ( # note parens, not square brackets
    # Big complex data structure
    # ...
    # ...
    # ...
    # ...
  );
}

then this will theoretically copy the entire list; but if the list
contains references it will only copy the references, and not the
things referred to. So it's still not a "deep" copy, but it's deeper
than the reference-based populate_x.

>> Subroutines are not just about code reuse. Which is more readable:
>>
>> my $x = [
>>   # Big complex data structure
>>   # ...
>>   # ...
>>   # ...
>>   # ...
>> ];
>>
<snip>
>>
>> my $x = populate_x();

<snip>
>
> I guess my only struggle there is that any perl person can read the perl
> code.  At first glance, I have no clue what "populate_x()" does because you
> gave it a name that's not in the camel book.

You can't write any meaningful program with just builtins; sooner or
later you have to use a subroutine. And a reader won't know exactly
what a function does just by looking at a call to it; but the reader
*shouldn't have to*. If the subroutine is hiding information the
reader needs, perhaps it was a poor choice of code to put in a
subroutine. But consider this:

use CGI;
my $cgi = CGI->new();

I don't know exactly what this function call did. I know that it
create a CGI object and populated it with initial data. I don't know
what that object is -- it could be a blessed hash, and blessed array,
even a blessed scalar ref. I don't know what initial data I got. But I
*don't have to care*, because all I care about is that I have an
object which will let me do things like this:

print $cgi->header,
         $cgi->start_html('hello world'),
         $cgi->h1('hello world'),
         $cgi->end_html;

And as long as these subroutines understand the low-level details of
what the $cgi object contains, I don't have to; because I'm dealing
only at the higher level, and the subroutines take care of all the
messy details for me. [At a deeper level, because I am isolated from
these details, the designer of CGI is free to totally change the
detailed implementation; and because he controls the only subroutines
which ever deal with a CGI object's implementation, he knows that
nobody's code will break.]

I know what these subroutines do through two means: the name and the
documentation. The name is very important; it needs to speak the
caller's language and be a short, clear summary of what the subroutine
does. The documentation is even more important: it is the subroutine
author's guarantee to you of what it does.

As a result, it might well be a mistake to write this:

my $x = populate_x();

for (@$x) {
    # Big
    # Complex
    # Operation
    # On
    # $_
}

because in this case, you've hidden how $x was initialized, and then
you've gone and written code which the reader can't understand without
knowing the details of what $x contains. But if the reader sees this:

my $x = create_x();

for my $p (@$x) { # The fact that x is an arrayref is noted in
create_x's documentation
   # but we don't have to care about the exact structure of the contents
   # of the array; they might be further arrayrefs or hashrefs or simple
   # scalar values; but we know that we can call process_p on them:
   process_p($p);
}

then the reader doesn't know what $x contains exactly, but they *don't
have to*. We make the details irrelevent, and hide them, so that the
reader can see the high-level ideas being thrown around.

In this case, it's a good bet that create_x and process_p might become
a module. If we define $p to be a Widget and $x to be an array of
Widgets, we might end up with:

package Widget;
sub create_widget_array {
   my $num = shift || 10; # allow user to specify number of Widgets
   my @x;
   for (1..$num) {
      push @x, create_widget(); # subroutine defined elsewhere
   }
   return \...@x;
}

sub process_widget {
   my $widget = shift;
   # process $widget in some way
   # we can choose whether to modify in place or to make a copy
   # and return that
   # this decision will have to be documented
   return $widget;
}

>>> Any suggestions?  Where can I read more on this stuff?  What questions
>>> should I be asking that I'm not smart enough to ask?
>>
>> The best that I can suggest is to read other people's code and ask
>> other people to read your code. Think of a specific example and come
>> up with a plan of how you would code it, and ask for criticism.
>
> No other perl programmers here, unfortunately.  Good advice, though.

Why don't you post your ideas here for criticism then? I wouldn't post
an entire several hundred line script, but you could post your
specification and your plan for writing a code which met said
specification. If you're following a tutor, you could do the exercises
and post your answers here for criticism.

Phil

--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to