Mostly, it's a problem of style. If you know what you are doing, it doesn't really matter. There are some pitfalls that you should be aware of, though.
Consider the following case, with subs on bottom, and calls to the subs on top. You see that there is a variable $stuff, declared before the sub. So you think it shouldn't be a problem to call your sub, which should print "ABCD". Unfortunately, it doesn't work like that. Your variable doesn't get initialized, because the program flow hasn't reached that point yet.
#!/usr/bin/perl -w
use strict;
dosomething();
my $stuff = "ABCD";
# bottom sub
sub dosomething {
print "$stuff\n";
}
OTOH, if you put your call to the sub at the end of the file, transforming your sub into a "top" sub, then you face the problem of unintended globals that Juerd is referring to. In the following case, your "dosomething" will work as expected, unless you call "dosomethingelse" first, in which case your lexical variable gets changed.
Using globals (including unintended ones) in this way is not recommended. If you really must have them, consider either creating a package or using closures.
#!/usr/bin/perl -w
use strict;
my $stuff = "ABCD"; # visible to all subs from now on
#top subs
{ # start closure
my $privatestuff = "WOW!"; #visible only from dosomething
sub dosomething {
print "$stuff \t $privatestuff\n";
}
} # end closure
sub dosomethingelse {
$stuff = "WXYZ";
}
dosomething();
Most of the problems that you might have with subs are related to using globals (or lexically scoped that act like globals) or not.
If your subs use parameters instead of globals, there are no such side effects when you call them, no matter where they are declared. The only difference will be that you have to use parentheses when you call subs that have not been defined yet.
#!/usr/bin/perl -w
use strict;
dosomething("ABCD");
#top subs
sub dosomething {
my $arg = shift;
print "$arg\n";
}
dosomething "EFGH";
My personal recommendation is: if you have a lot of subs, consider making a module out of them.
HTH
_ _ _ _
(_|| | |(_|><
_|
| [reply] [Watch: Dir/Any] [d/l] [select] |
But I have heard here and other places online that it is better to place it on top.
It is. Placing them at the top avoids sharing of ALL lexically scobed variables in the file scope ("unintended globals"). It also allows you to not write parens (which isn't really a problem if you like parens anyway).
Have a look at this recent meditation: where do you put your subs.
Especially demerphq's posts. (and mine of course *grin*)
U28geW91IGNhbiBhbGwgcm90MTMgY
W5kIHBhY2soKS4gQnV0IGRvIHlvdS
ByZWNvZ25pc2UgQmFzZTY0IHdoZW4
geW91IHNlZSBpdD8gIC0tIEp1ZXJk
| [reply] [Watch: Dir/Any] |
Thanks millions for all your help, everyone! One thing I have noticed, seeming this is my first attempt to learn any programming language, is there is never just one way to do things. Everyone has their own way to set things up, kinda gets confusing as a newbie when one person tells you to do this while others say now :) Gotta love perl though, too addicting. Thanks everyone!
| [reply] [Watch: Dir/Any] |
Unless one of the reasons above, I put my subs at the bottom. Lexical scoped variables that should be visible throughout at the top of the file. If I want to hide anything, I'll put the lexically scoped variables and the subs for them in their own enclosing block. The way I code, "unintended" globals are not a problem. I always use my on everything in a sub, unless... the referenced variable is supposed to be visible to the sub from outside. In general, globals usually are bad but some people would make it out to be a most vile offense. Like most things, they have their place.
-Lee
"To be civilized is to deny one's nature." | [reply] [Watch: Dir/Any] |
On a side note...
If you use prototypes and the sub appears on the bottom (or after the invocation), the prototype will not work as intended. You'll get a "main::subroutine called too early to check prototype" warning and the prototype will not/cannot be checked. When using prototypes, you'll need to either place the sub before its invocation or declare the sub and its prototype:
sub prototest($); # declare sub and prototype
prototest( 4 ); # dies if no param or more than 1 param is passed
sub prototest($){
print '1, 2, 3, ', @_;
}
-or-
sub prototest($){
print '1, 2, 3, ', @_;
}
prototest( 4 ); # dies if no param or more than 1 param is passed
| [reply] [Watch: Dir/Any] [d/l] [select] |