I'm not even sure how to ask this question, but here goes:
I struggle knowing how to structure my code, what things belong as their own
subroutines and what things can stay in the main script. How do the smart
guys make these decisions?
For example, let's say I need to:
1. Read a complex file
2. Populate a complex dataset
3. Accept user input
4. Based on user input, either modify or add to dataset, or quit
5. Update files on disk
6. Go to step #3
Which steps should be their own subroutines vs. just writing them into the
main part of the script? And how did you make that decision?
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.
Any suggestions? Where can I read more on this stuff? What questions
should I be asking that I'm not smart enough to ask?
TIA.
- Bryan
If you like, put everything in its own subroutine, call the main one
"main", and reduce the main part of your script to just this:
main();
If you want a more OO-style script, you might have:
my $x = Myprogram->new();
$x->main();
> 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.
Subroutines are not just about code reuse. Which is more readable:
my $x = [
# Big complex data structure
# ...
# ...
# ...
# ...
];
my $y = [
# Big complex data structure
# ...
# ...
# ...
# ...
];
for my $p ($x) {
for my $q ($y) {
#Big
# complex
# multi-statement
# manipulation
# of
# $p
# and
# $q
}
}
Or this:
my $x = populate_x();
my $y = populate_y();
for my $p (@$x) {
for my $q (@$y) {
process_pq($p, $q);
}
}
Or even:
my $x = populate_x();
my $y = populate_y();
process_xy($x, $y); # xy_process now contains the for loops
The point is that in the first version, you are constantly bouncing
from the big-picture ideas to the low-level messy details. By
abstracting code out into subroutines populate_x(), populate_y() and
process_xy(), you have the main script which deals in big ideas, and
three subroutines which deal with messy details. A subroutine should
do one thing, and do it well.
> 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.
Phil
Well, there is one school of programming that insists that no subroutine
should be larger than 42 lines (see, it is the answer to everything).
I would separated the user I/O and the dataset I/O into their own
modules so that future changes to them will be isolated.
--
Just my 0.00000002 million dollars worth,
Shawn
Programming is as much about organization and communication
as it is about coding.
I like Perl; it's the only language where you can bless your
thingy.
> Bryan R Harris wrote:
>>
>> I'm not even sure how to ask this question, but here goes:
>>
>> I struggle knowing how to structure my code, what things belong as their own
>> subroutines and what things can stay in the main script. How do the smart
>> guys make these decisions?
>>
>> For example, let's say I need to:
>>
>> 1. Read a complex file
>> 2. Populate a complex dataset
>> 3. Accept user input
>> 4. Based on user input, either modify or add to dataset, or quit
>> 5. Update files on disk
>> 6. Go to step #3
>>
>> Which steps should be their own subroutines vs. just writing them into the
>> main part of the script? And how did you make that decision?
>>
>> 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.
>>
>> Any suggestions? Where can I read more on this stuff? What questions
>> should I be asking that I'm not smart enough to ask?
>>
>> TIA.
>>
>> - Bryan
>
> Well, there is one school of programming that insists that no subroutine
> should be larger than 42 lines (see, it is the answer to everything).
Let me guess, the number of lines on a standard terminal in the old days?
=)
> I would separated the user I/O and the dataset I/O into their own
> modules so that future changes to them will be isolated.
Makes sense.
- Bryan
>> 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.
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.
> The point is that in the first version, you are constantly bouncing
> from the big-picture ideas to the low-level messy details. By
> abstracting code out into subroutines populate_x(), populate_y() and
> process_xy(), you have the main script which deals in big ideas, and
> three subroutines which deal with messy details. A subroutine should
> do one thing, and do it well.
This is terrific advice.
>> 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.
- Bryan
No, that was 25. But the last line was used for status by both vi and
emacs, so:
perl -le 'print scalar reverse "24"'
Actually, the number varies from as low as 20 to as high as 60. 60
being the number of lines you can print on US letter paper. 42 is just
somewhat reasonable.
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-...@perl.org
> For additional commands, e-mail: beginne...@perl.org
> http://learn.perl.org/
>
>
>
> The point is that in the first version, you are constantly bouncing
> from the big-picture ideas to the low-level messy details. By
> abstracting code out into subroutines populate_x(), populate_y() and
> process_xy(), you have the main script which deals in big ideas, and
> three subroutines which deal with messy details. A subroutine should
> do one thing, and do it well.
>
Check out literate programming <http://www.literateprogramming.com/>. It
moves big-picture ideas into the structure. Then you can add subroutines
where they make sense - for code used by more than one place.
Leo <http://webpages.charter.net/edreamleo/front.html> is a pretty nice tool
fro writing programs in a literate style.
--
Robert Wohlfarth
[stuff cut out]
>> 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.
>>
> You pass as a refernce as ni
> called_sub(\@d);
> Now when you update, you are updating @d and not a copy.
>
> If you have any questions and/or problems, please let me know.
> Thanks.
>
> Wags ;)
> David R. Wagner
So let's say I pass a reference to an array:
my @d = (1,2,3);
called_sub(\@d);
... but then in called_sub, accessing that gets a lot "noisier", right?
sub called_sub {
my $d = shift;
push @{$d}, 2; # I'd rather be able to use @var instead of @{$var}
}
Is there any way to make a new variable, @something, that is just another
name for the array that was passed in by reference? Since I'm building a
complex data structure, having to include all those @{}'s can get annoying.
Also, if called_sub modifies that array that was passed in by reference,
does it stay changed outside the subroutine? Or do I have to return
something from the subroutine and capture it on the outside?
Thanks!!
- Bryan
ps. Out of curiosity, what does "wags" mean?
A couple responses, mixed in below:
> 2009/12/11 Bryan R Harris <Bryan_R...@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:
What's the difference between pointers and references? Where can I read
about that difference?
If the data structures being referenced (?) by those references are created
within the subroutine with "my", are they still alive and accessible outside
the subroutine? Or do they go away after you return?
Neat!
No tutors here either. I think I'm the tutor for other people. =)
I will do that, though. Thanks! Great response, I loved reading it.
- Bryan
First of all, often just "@$d" instead of "@{$d}" will work too. This will
make things a little less noisy. Otherwise, you can try using perltie
(possibly not very recommended) to tie a regular variable into the reference.
Alternatively, you can use this module:
http://search.cpan.org/dist/Lexical-Alias/
Or another option I can think of is to create an object to wrap the operations
around the reference, and use methods on it:
<<<
my $d = MyArrayHandle->($d_param);
$d->push(@other_array);
>>>
TIMTOWTDY. And in Perl 6 one will be able to pass arrays as first-order
parameters to the subroutine.
>
> Also, if called_sub modifies that array that was passed in by reference,
> does it stay changed outside the subroutine? Or do I have to return
> something from the subroutine and capture it on the outside?
It stays changed outside the subroutine:
<<<<<<<<<<<<
#!/usr/bin/perl
use strict;
use warnings;
sub change_array_ref
{
my $a_ref = shift;
$a_ref->[5] = 5_000;
return;
}
my @array = (1 .. 10);
change_array_ref(\@array);
print join(", ", @array), "\n";
>>>>>>>>>>>>
prints:
<<<<<<<<
1, 2, 3, 4, 5, 5000, 7, 8, 9, 10
>>>>>>>>
That's part of the point of references. If you're interested in having a
temporary variable, you can use a shallow copy ("[ @{$array_ref} ]") or a deep
copy - see perldoc Storable.
Regards,
Shlomi Fish
--
-----------------------------------------------------------------
Shlomi Fish http://www.shlomifish.org/
"Star Trek: We, the Living Dead" - http://shlom.in/st-wtld
Bzr is slower than Subversion in combination with Sourceforge.
( By: http://dazjorz.com/ )
>
>
> [stuff cut out]
>
>>> 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.
>>>
>> You pass as a refernce as ni
>> called_sub(\@d);
>> Now when you update, you are updating @d and not a copy.
>>
>> If you have any questions and/or problems, please let me know.
>> Thanks.
>>
>> Wags ;)
>> David R. Wagner
>
>
> So let's say I pass a reference to an array:
>
> my @d = (1,2,3);
> called_sub(\@d);
>
> ... but then in called_sub, accessing that gets a lot "noisier", right?
>
> sub called_sub {
> my $d = shift;
> push @{$d}, 2; # I'd rather be able to use @var instead of @{$var}
> }
As Shlomi pointed out, you can refer to the entire array as @$d. The largest
index is $#$d.
You can refer to elements using the $d->[0] syntax, which is equivalent to
${$d}[0].
If the array isn't too large, and you don't need to modify the original
array, you can just make a copy and use that in the subroutine:
my @copy = @$d;
>
> Is there any way to make a new variable, @something, that is just another
> name for the array that was passed in by reference? Since I'm building a
> complex data structure, having to include all those @{}'s can get annoying.
Elements of a hash referenced by $h can be accessed by $h->{key}. Nested
structures can sometimes be simplified: $h->{key1}->[key2} is a two-level
nested hash, which can be simplified to $h->{key1}{key2}. The array-of-array
element ${${$a}[2]}[3] can be written as $a->[2]->[3], which can be
simplified to $a->[2][3], and so on.
>
> Also, if called_sub modifies that array that was passed in by reference,
> does it stay changed outside the subroutine? Or do I have to return
> something from the subroutine and capture it on the outside?
If you pass an array by reference, there is no copy in the subroutine. Any
changes you make to the array in the subroutine will be retained in the
calling program after the subroutine returns.
You can use dclone() from Storable to copy deeply-nested data
structures. See `perldoc Storable` or http://perldoc.perl.org/Storable.html
The key difference in my mind is this: Perl references are defined in
terms of perl datatypes. C pointers are defined (more or less) in
terms of memory locations.
If you think about Perl references in terms of *what they do* and not
*how they work*, it becomes much clearer. There is nothing you can do
to a perl reference to get its "memory address", so that doesn't fit
within the conceptual framework of Perl references. Perl references
are simply scalar values which provide an indirect form of access to
other perl objects (including scalars, hashes, OO types...). You can
create a reference from a named or anonymous variable, and you can
dereference that reference to get the original object. You can think
of them as labels or tags or handles; all of these ideas fit the
paradigm created by the interface of the reference.
C pointers, however, let you do so much more, most of it unsafe. They
let you add arbitrary integers to pointers; this may well end up with
an invalid pointer value. They let you subtract one pointer from
another to find out the distance in memory locations between object A
and object B. The interface suggests that a pointer is a memory
location value, much more than a label on a variable.
Note that this thinking in terms of what it does applies to other
datatypes. For example: the CGI module is a module which helps write
CGI scripts. It emits HTTP headers and lets you write HTML in a
Perl-like way. As a user of this module, you don't start with
implementation details such as "The CGI module stores state about the
HTTP connection to determine which MIME types the client can read. To
parse this Content-Accept: header, it uses the following regexes..."
Instead, you talk about what it does:
$q = CGI->new; # create new CGI object
print $q->header, # create the HTTP header
$q->start_html('hello world'), # start the HTML
$q->h1('hello world'), # level 1 header
$q->end_html; # end the HTML
The same thinking applies to references: forget about what they are
under the hood. Think only in terms of what they do.
> If the data structures being referenced (?) by those references are created
> within the subroutine with "my", are they still alive and accessible outside
> the subroutine? Or do they go away after you return?
They're still alive. Perl objects are not harvested by the GC until
there are no more references to them. So this is perfectly safe:
sub anon_scalar { my $x; return \$x}
my $ref = anon_scalar;
$$ref = 3;
Phil
>> 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.
Okay, here's one I struggle with often -- is one of these better than the
other?
**************************************
A.
if ( isFlat($tire) ) { changeTire($tire); }
B.
checkFlatAndChangeTireIfNecessary($tire);
**************************************
"changeTire" feels more elemental (?) and therefore more useful, but I can
see why (B) would be attractive too...
(B) is a ridiculous subroutine name, but at least someone would know what's
going on with it. I started with just "checkTireAndChange", but how would I
remember in 6 months that it only checks for flats and not nails?
TIA.
- Bryan
Why not?
isFlat($tire) and changeTire($tire);
or
$tire->isFlat() and $tire->change( $spare );
> You pass as a refernce as ni
> called_sub(\@d);
> Now when you update, you are updating @d and not a copy.
No need to use a reference for that:
perl -wle '
sub inc{ ++$_ for @_ }
my @x = 1 .. 5;
inc @x;
print "@x";
'
2 3 4 5 6
--
Ruud
Ah, a recovering Java programmer :-)
Seriously, the letsRunAsManyWordsAsPossibleTogether style bugs the heck
out of me. The Perlish style (perldoc perlstyle) would be
check_flat_and_change_tire_if_necessary( $tire )
and I agree with Shawn's suggestion of object methods. But even if you
don't use objects, you can clearly remove at least some redundancy:
check_flat_and_change_if_necessary( $tire )
Personally I would, all things being equal, probably write that as
is_flat( $tire) and change_tire( $tire )
putting the "tire" back in because a subroutine named just "change" is too
vague. Oh, I see that's exactly what Shawn had. GMTA :-) There is also
change_tire( $tire ) if is_flat( $tire );
depending on what you think is more important, the changing or the
checking. TIMTOWDI.
The question you pose is one I see raised often in Java circles. It comes
up rarely among Perl programmers. Possibly because we do not use nearly
as many IDEs and automated refactoring tools. Neither will you find Perl
programmers enamored of Hungarian notation, for instance. But remember
that in Java these would be method calls anyway. Design Patterns in Perl
look rather different. Many design patterns exist only to solve problems
that don't exist in Perl (think typing).
Java programmers are far more obsessed with learning correct ways of
structuring methods. I find their discussions interesting but mostly
academic. As long as my methods and subroutines are under a screen's
length each and reusability is maximized (Don't Repeat Yourself), I'm
happy. Whether the condition goes inside or outside the subroutine may
depend on usage.
The older I get, the shorter my methods get.
--
Peter Scott
http://www.perlmedic.com/
http://www.perldebugged.com/
http://www.informit.com/store/product.aspx?isbn=0137001274
That's because there are few datatypes in Perl but context is
everything. It's hard to describe context using Hungarian notation. :)
There is one other question about B. that I haven't seen mentioned in
this thread. There may be other reasons why you would change that tire.
Would you really want it bound that tightly with CheckFlat() when you
need to add them?
Bob McConnell
>> Is there any way to make a new variable, @something, that is just another
>> name for the array that was passed in by reference? Since I'm building a
>> complex data structure, having to include all those @{}'s can get annoying.
>
> Elements of a hash referenced by $h can be accessed by $h->{key}. Nested
> structures can sometimes be simplified: $h->{key1}->[key2} is a two-level
> nested hash, which can be simplified to $h->{key1}{key2}. The array-of-array
> element ${${$a}[2]}[3] can be written as $a->[2]->[3], which can be
> simplified to $a->[2][3], and so on.
This is great advice. I often end up with things like @{$a{$i}{$j}}[4,7,9],
which can be a little painful both to write and to read, but I think this
will help...
Thanks, Jim.
- Bryan
> On Wed, 16 Dec 2009 17:47:16 -0600, Bryan R Harris wrote:
>> Okay, here's one I struggle with often -- is one of these better than
>> the other?
>>
>> **************************************
>> A.
>> if ( isFlat($tire) ) { changeTire($tire); }
>>
>> B.
>> checkFlatAndChangeTireIfNecessary($tire);
>>
>> **************************************
>
> Ah, a recovering Java programmer :-)
I wish -- I've never done much more than perl and Visual basic I just pick
up bad habits easily. =)
> Seriously, the letsRunAsManyWordsAsPossibleTogether style bugs the heck
> out of me. The Perlish style (perldoc perlstyle) would be
>
> check_flat_and_change_tire_if_necessary( $tire )
For some reason I thought underscores were deprecated in subroutine names,
though I'm glad to be corrected.
> and I agree with Shawn's suggestion of object methods. But even if you
> don't use objects, you can clearly remove at least some redundancy:
>
> check_flat_and_change_if_necessary( $tire )
>
> Personally I would, all things being equal, probably write that as
>
> is_flat( $tire) and change_tire( $tire )
>
> putting the "tire" back in because a subroutine named just "change" is too
> vague. Oh, I see that's exactly what Shawn had. GMTA :-) There is also
>
> change_tire( $tire ) if is_flat( $tire );
>
> depending on what you think is more important, the changing or the
> checking. TIMTOWDI.
Mostly my question was about how to decide the extent of a subroutine's
functionality.
> The question you pose is one I see raised often in Java circles. It comes
> up rarely among Perl programmers. Possibly because we do not use nearly
> as many IDEs and automated refactoring tools. Neither will you find Perl
> programmers enamored of Hungarian notation, for instance. But remember
> that in Java these would be method calls anyway. Design Patterns in Perl
> look rather different. Many design patterns exist only to solve problems
> that don't exist in Perl (think typing).
>
> Java programmers are far more obsessed with learning correct ways of
> structuring methods. I find their discussions interesting but mostly
> academic. As long as my methods and subroutines are under a screen's
> length each and reusability is maximized (Don't Repeat Yourself), I'm
> happy. Whether the condition goes inside or outside the subroutine may
> depend on usage.
>
> The older I get, the shorter my methods get.
That's good advice. Great advice, actually.
In fact, I think what I'm coming to after all this discussion is this:
design your script so that your logic is as readable and clear as possible,
then your subroutines will just need to support that design.
Does that sound defensible?
Thanks.
- Bryan
Ah, yes, that's the kind of advice I thought I was looking for with the
question.
I've been trying to generalize all this advice, but my previous message is
the closest I've come to it.
Thanks Bob.
- Bryan
>> What's the difference between pointers and references? Where can I read
>> about that difference?
>
> The key difference in my mind is this: Perl references are defined in
> terms of perl datatypes. C pointers are defined (more or less) in
> terms of memory locations.
>
> If you think about Perl references in terms of *what they do* and not
> *how they work*, it becomes much clearer. There is nothing you can do
> to a perl reference to get its "memory address", so that doesn't fit
> within the conceptual framework of Perl references. Perl references
> are simply scalar values which provide an indirect form of access to
> other perl objects (including scalars, hashes, OO types...). You can
> create a reference from a named or anonymous variable, and you can
> dereference that reference to get the original object. You can think
> of them as labels or tags or handles; all of these ideas fit the
> paradigm created by the interface of the reference.
This is exactly what I needed, thanks Philip!
- Bryan
FYI, the reason we wanted a reference was because the data set might end up
being huge.
Uh, come to think of it, I'm surprised your script does what it does. I'd
have thought that the changes made internal to inc would've stayed there
since they're not being "returned". This bothers me a little...
- Byan
@_ contains aliases to the variables. So you can do (untested):
<<<<<<<<<
sub modify_var
{
$_[0] += 100;
return;
}
my $x = 5;
modify_var($x);
# $x is now 105.
>>>>>>>>>
However, note that I consider tricks like that as a bad idea and prefer to use
references if I wish to do it. using << my $x = shift; >> or << my ($x) = @_;
>> will not keep the aliasing. That's how the Perl 5 implementation works.
Regards,
Shlomi Fish
--
-----------------------------------------------------------------
Shlomi Fish http://www.shlomifish.org/
Freecell Solver - http://fc-solve.berlios.de/
>> perl -wle '
>>
>> sub inc{ ++$_ for @_ }
>>
>> my @x = 1 .. 5;
>>
>> inc @x;
>>
>> print "@x";
>> '
>> 2 3 4 5 6
>
>
> FYI, the reason we wanted a reference was because the data set might end up
> being huge.
FYI, there is no issue.
> Uh, come to think of it, I'm surprised your script does what it does. I'd
> have thought that the changes made internal to inc would've stayed there
> since they're not being "returned". This bothers me a little...
It shouldn't bother you, it should make you aware that parameters in
Perl are aliases, so there is no content copying happening until you
code it.
perl -wle'
my @x = 0 .. 3;
print "@x";
++$_ for grep $_, @x;
print "@x";
++$_ for map $_, @x;
print "@x";
'
--
Ruud
See below for my response.
I appreciate all your help on the channel. However, I noticed that you keep
giving examples as one big perl -wle '....' block (with single-quotes). This
is:
-->
1. Error prone. What if someone changes the program to include a single-quote?
2. Won't work properly on Win32's CMD.EXE , which we may unfortunately still
need to accommodate for.
3. Very hard to experiment with on the shell, due to scrolling between such
large numbers.
4. Doesn't follow best practices of using "use strict;", "use warnings;", etc.
<--
As a result, I believe it would set a bad example, and that people may mis-
interpret it.
I suggest that instead you (or whoever) delimit a block using <<<< and >>>> or
{{{{ and }}}} or whatever you want and include a Perl program that you've
tested inside a file. E.g:
<<<<<<<<<<<<<
#!/usr/bin/perl -l
use strict;
use warnings;
my @x = 0 .. 3;
print "@x";
++$_ for grep $_, @x;
print "@x";
++$_ for map $_, @x;
print "@x";
>>>>>>>>>>>>>
Which ives me:
<<<<<<<<<<
shlomi:~$ perl test2.pl
0 1 2 3
0 2 3 4
0 2 3 4
>>>>>>>>>>
Which seems right.
Regards,
Shlomi Fish
--
-----------------------------------------------------------------
Shlomi Fish http://www.shlomifish.org/
First stop for Perl beginners - http://perl-begin.org/
> Bryan R Harris wrote:
>
>>> perl -wle '
>>>
>>> sub inc{ ++$_ for @_ }
>>>
>>> my @x = 1 .. 5;
>>>
>>> inc @x;
>>>
>>> print "@x";
>>> '
>>> 2 3 4 5 6
>>
>>
>> FYI, the reason we wanted a reference was because the data set might end up
>> being huge.
>
> FYI, there is no issue.
Is this because the parameters are passed as aliases??? Wow, I had no
idea...
>> Uh, come to think of it, I'm surprised your script does what it does. I'd
>> have thought that the changes made internal to inc would've stayed there
>> since they're not being "returned". This bothers me a little...
>
> It shouldn't bother you, it should make you aware that parameters in
> Perl are aliases, so there is no content copying happening until you
> code it.
>
>
> perl -wle'
>
> my @x = 0 .. 3;
> print "@x";
>
> ++$_ for grep $_, @x;
> print "@x";
>
> ++$_ for map $_, @x;
> print "@x";
> '
(I'm not smart enough to understand what this code is supposed to be
teaching me.)
Thanks for the point above, though, I wish I'd known that years ago.
- Bryan
<snip>
>
> Regards,
> Shlomi Fish
Dr. Ruud,
I disagree with Mr. Fish's suggestion that you quit using
command line scripts for your examples. I often find them very helpful.
I can cut/paste them from mutt to the command line and see how they work
on my system, tweak them, break them and learn from them without the
necessity of creating a file. I personally find it very easy to
experiment from the shell and do so often. I only use strict and warnings
on the CLI if something doesn't work and the reason is not immediately
evident. His second objection is certainly true but I've never seen a
requirement here that 'one size fit all'.
I have saved many snippets of your code and find your additions to
the list most worthwhile. Please don't let the critics and nitpickers
limit the valuable help you dispense here.
Thanks,
Mike McClain
--
Satisfied user of Linux since 1997.
O< ascii ribbon campaign - stop html mail - www.asciiribbon.org