Re^2: why avoid & on function call
by choroba (Cardinal) on Dec 27, 2020 at 17:32 UTC
|
The placement of a sub is important onlymainly when you call it without parentheses, i.e. as a bareword. When such a call is being parsed, the subs already parsed are recognised and the bareword is parsed as their call, otherwise without strict, the bareword is stringified, and with strict, you get an error.
#!/usr/bin/perl
use warnings;
print "", frob(); # 12
print "", frob; # frob
use strict;
print "", frob(); # 12
# print "", frob;
sub frob {
12
}
Uncommenting the last last print line would make the source unparsable with Bareword "frob" not allwoed while "strict subs" in use
Updated: as shown in the text, thanks kcott.
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] [select] |
|
$ perl -wE '
sub meaning () { 42 }
say meaning();
'
42
$ perl -wE '
say meaning();
sub meaning () { 42 }
'
main::meaning() called too early to check prototype at -e line 2.
42
You can, of course, predeclare and leave the definition for later:
$ perl -wE '
sub meaning ();
say meaning();
# ... later in code with other subroutine defintions
sub meaning () { 42 }
'
42
| [reply] [d/l] [select] |
|
DB<188> sub frob; frob(1,2,3); sub frob { say "@_" }
1 2 3
DB<189>
| [reply] [d/l] [select] |
Re^2: why avoid & on function call
by chromatic (Archbishop) on Dec 27, 2020 at 17:34 UTC
|
others place them at the start because of the behaviour when not using the ampersand
Another reason is to avoid accidentally closing over lexical variables declared outside of function scope.
| [reply] |
Re^2: why avoid & on function call (pre-declaration)
by LanX (Saint) on Dec 27, 2020 at 18:17 UTC
|
Post-declared subs are always resolved as long as Perl knows that it's a sub, that's why Perl5 introduced the "new syntax" ° with parenthesis func()
Pre-declaration is only necessary when avoiding parens in bareword use, like func 1,2,3 because otherwise Perl can't tell at the first parse if its a sub-call or not.
A pre-declaration placeholder can be done by a body-less sub NAME; or with the pragma use subs LIST for multiple names.
Using &ersands just to spare parens() has too many side-effects and should be limited to cases which can't be resolved by pre-declaration.
°) "new" as in "new york", "new model army" or "Bojo Churchill". | [reply] [d/l] [select] |
|
| [reply] [d/l] |
|
> So I don't envisage me using this pre-declaration very much but it's good to know it exists.
There are use cases, like plugin systems or delayed compilation on demand.
NB: prototypes can be pre-declared too, so just applying parenthesis instead of ampersand wouldn't help, if you want an explicit prototype check.
| [reply] |
Re^2: why avoid & on function call
by talexb (Chancellor) on Dec 27, 2020 at 19:04 UTC
|
Putting subroutines first was important back in the days when compilers were less advanced. So you declared a bunch of routines at the top of the file, and then at the end of your file you had the main routine that called them all.
These days, that's not necessary. From a style point of view (he said, donning his asbestos firesuit), I like having the 'main' part of the routine first, so that at a quick glance of the file, I can see what's going on. If I want further detail, I can scroll down to look at the routines I'm interested in.
And to address the use of '&', the short answer is Don't Use It. The long answer is, Use It If You Understand What It's Doing And You Actually Really Do Need That Behaviour.
Alex / talexb / Toronto
Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.
| [reply] [d/l] |
|
From a style point of view (he said, donning his asbestos firesuit), I like having the 'main' part of the routine first, so that at a quick glance of the file, I can see what's going on. If I want further detail, I can scroll down to look at the routines I'm interested in.
We style things the same :)
It is very rare that I arrange code differently to this.
Usually I add an explicit exit statement to the end of the 'main' part of the code before the subroutines so it is obvious where the 'main' block ends.
| [reply] [d/l] |
|
#!/usr/bin/perl
use strict;
use warnings;
# Base 24 question from https://twitter.com/pwnallthethings/status/13
+43590455511023621
my @digits = qw/B C D F G H J K M P Q R T V W X Y 2 3 4 6 7 8 9/;
my %digit_value;
my $string = 'FCKGW-RHQQ2-YXRKT-8TG6W-2B7Q8';
# Convert a base 24 number to decimal. This is a group of five
# numbers, like a Windows key.
{
my $v = 0;
foreach my $d ( @digits ) {
$digit_value{ $d } = $v++;
}
my @units = split ( /-/, $string );
foreach my $u ( @units ) {
my $value = decode ( $u );
print "$u -> $value\n";
}
}
sub decode
{
my ( $str ) = @_;
my $val = 0;
my @chars = split ( //, $str );
foreach my $c ( @chars ) {
$val *= 24;
$val += $digit_value{ $c };
}
return $val;
}
There's no exit required because the closing brace indicates "That's the end!" to Perl. I have seen code where the mainline is right up against the left margin -- I never code like that, because it obscures what's going on -- it's the same level as the use statements, so I don't know where the declarations end and the executable code starts.
And I don't put an exit anywhere, because that would indicate I was bailing out early, instead of allowing the syntax to naturally indicate where the end of the procedure is. To be clear, I'm *not* saying your way is wrong -- it's just not what I prefer. I like my way because it's clear and legible. For me, white space is my friend.
Alex / talexb / Toronto
Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.
| [reply] [d/l] [select] |
|
> Usually I add an explicit exit statement to the end of the main part of the code before the subroutines so it is obvious where the main block ends.
exit doesn't end scope.
If you have variables declared in your main part, they could accidentally leak as closures into the subs.
Using sub main { BLOCK } is one way to limit the scope.
I personally rather use a naked { BLOCK }
Like this the distinction to intentionally file-scoped variables outside this main BLOCK becomes obvious.
| [reply] [d/l] [select] |
|
"Usually I add an explicit exit statement to the end of the 'main' part of the code before the subroutines so it is obvious where the 'main' block ends."
Meh, use an editor that folds sub code, and it's impossible not to easily see where main ends and subs begin.
I'm with talexb on the exit... to me, exit indicates an early emergency-type return. Although I don't put my main code within a block, I don't use exit either. I do though always put my main code before all of the sub definitions, unless there's a very good reason not to.
An exception to the main section blocks is in my test files. Each of my test files typically tests a single subroutine, and I like a pristine environment for every set of tests (eg. bad parameters, first parameter valid/invalid, second parameter valid/invalid etc), again with folding ability. eg:
# bad params
{code-block}
# validate date param format
{code-block}
# validate date param range
{code-block}
...
I thought I wrote up an article once here on Perlmonks regarding folding Perl code, and turns out I was right. I also have a screenshot. | [reply] [d/l] [select] |