Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Re: why avoid & on function call

by Bod (Parson)
on Dec 27, 2020 at 17:08 UTC ( [id://11125795]=note: print w/replies, xml ) Need Help??


in reply to why avoid & on function call

From a rather limited viewing of other people's code, I have noticed that some Perl programmers tend to place their subroutines at the start of the code. Personally I have always tended to place them at the end and have always assumed others place them at the start because of the behaviour when not using the ampersand.

Replies are listed 'Best First'.
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]
      "The placement of a sub is important only when you call it without parentheses, ..."

      I disagree with the inclusion of the word only in that statement. Here's a situation where placement is important when parentheses are used:

      $ 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

      — Ken

      Bareword use without parens is also the reason why the sub NAME; syntax without function {BODY} exists.

      One can pre-declare functions for the first parse, which are later defined (or resolved via AUTOLOAD)

      DB<188> sub frob; frob(1,2,3); sub frob { say "@_" } 1 2 3 DB<189>

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

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.


    Improve your skills with Modern Perl: the free book.

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 &ampersands just to spare parens() has too many side-effects and should be limited to cases which can't be resolved by pre-declaration.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

    °) "new" as in "new york", "new model army" or "Bojo Churchill".

      A pre-declaration placeholder can be done by a body-less sub NAME;

      Thanks LanX - I didn't know this was an option. Although in the past I have habitually added an ampersand which I have been doing less and less over the last year or so in favour of always applying parenthesis. So I don't envisage me using this pre-declaration very much but it's good to know it exists.

        > 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.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

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.

      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.

          Usually I add an explicit exit statement to the end of the 'main' part of the code ..

        I don't .. because I use braces for my 'mainline' code. Here's a recent script I wrote based on something I saw on Twitter:

        #!/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.

        > 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.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

        "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.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11125795]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (2)
As of 2024-04-25 20:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found