ampersand subroutine

Discussion in 'Perl Misc' started by Guy, May 19, 2009.

  1. Guy

    Guy Guest

    I've seen some code that call user subroutines without the ampersand. I
    didn't know you could do that.

    "BTW, I went out and bought Learning Perl to help with my Intermediate
    Perl."

    So I read that you can omit the ampersand if "the compiler sees the
    subroutine definition before invocation or..."

    But instead of declaring all my subroutines at the begining of my script, or
    ensuring they're located ahead of invocation, wouldn't it just be safer and
    even easier to always have the ampersand? or are ampersand really a thing of
    the past when not absolutely needed?

    Guy
     
    Guy, May 19, 2009
    #1
    1. Advertisements

  2. It has different semantics, so it depends upon what you want/need.
    You got the wrong idea. Actually several wrong ideas.
    1: where if not at the beginning of your script do you define your subs?
    You don't do that in the middle of the main body, do you?
    2: as you wrote correctly the declaration has to be before the
    invocation, while the definition of the sub can be anywhere, even
    textually after its invocation
    3: the ampersand is not "a thing of the past". It modifies the calling
    semantic, such that
    a) prototypes are overridden
    b) @_ is visible to the called sub
    (for details see perldoc perlsub).
    If you want that semantic (which IMO is somewhat screwy) then use
    ampersands. For normal programs it causes too many unwanted
    dependencies, so I advise against using them. It is just easier not
    having to deal with them.

    jue
     
    Jürgen Exner, May 19, 2009
    #2
    1. Advertisements


  3. (with a subtext of "you almost never want the semantics that ampersand gives")



    Where did you read it?



    The above was a rhetorical question, as I recognize that quote
    from the Llama book.

    You snipped the part after the "or":

    if Perl can tell from the syntax that it's a subroutine call

    All of my code makes use of that snipped part.



    I define my subroutines at the end of my program, after the main code.

    I do not declare my subroutines either.

    ("define" and "declare" mean different things.)

    Yet I never use ampersand on subroutine calls.


    So how do my programs end up working then?

    I make use of the part after the "or"...

    .... I always use parenthesis when calling my user-defined subroutines.



    Both approaches have "safety" issues.

    Using the ampersand may invoke the often unwanted semantics mentioned below.

    Using only parenthesis may call a built-in subroutine with the
    same name rather than the user-defined subroutine.


    I do it at the end.


    .... or you must use parenthesis around the argument list.


    Debugging when the ampersand approach is used can be really tricky.

    Debugging when the parenthesis approach is used is easy. Just do a

    perldoc -f my_func

    If it returns docs for my_func(), then choose a different name
    for your user-defined subroutine.

    So as Jürgen said, it is not a thing of the past.

    However, the "when not absolutely needed" part _is_ correct.

    The ampersand is absolutely needed if you want the above special
    treatment of the sub's argument list or if you insist on using
    the same name as a built-in.

    It is rare to want or need the arg special treatment, and I do not
    recommend reusing the name of a built-in Perl function.


    So if you follow a simple rule, you won't have much to worry about:

    Never use ampersand on subroutine calls, always use parenthesis
    on (user-defined) subroutine calls (but watch out for name collisions)
     
    Tad J McClellan, May 19, 2009
    #3
  4. Guy

    ccc31807 Guest

    Absolutely! In general, you might find yourself writing 'main' code
    that's simply a sequence of function calls with only a few lines of
    code, and your functions defined AFTER your program exits, and a
    separate section, labled and documented.

    Or better yet, if you have a number of user defined functions, in
    modules with descriptive names, like a C program with a very short
    main function but a number of include files that contain your
    functionality.

    CC
     
    ccc31807, May 19, 2009
    #4
  5. Guy

    News123 Guest

    i Juergen,

    I'm a little surprised by one of Guy's and one of your statements.



    Please see my example at the end of the post.
    the function is declared after the call and things work fine.

    @_ is also visible in my example, but you say the ampersand is needed.
    I guess you mean soething different, but I don't understand it.

    My example:
    ----------------
    use strict;
    use warnings;
    require 5.000;
    func1(1,2,3);
    func2(4,5,6);
    exit(0);

    # ##############################################################
    # now only function declarations (after the "function calls"
    # the question is whether I should do this and what damage
    # is done if I do it.
    #
    sub func1 {
    print "I am func 1 and my args are <",join("> <",@_),">\n";
    func2(@_);
    }


    sub func2 {
    print "I am func 2 and my args are <",join("> <",@_),">\n";
    }
     
    News123, May 19, 2009
    #5
  6. Guy

    Uri Guttman Guest

    N> @_ is also visible in my example, but you say the ampersand is needed.
    N> I guess you mean soething different, but I don't understand it.

    you don't get the docs. it is not that @_ is 'visible'. when you call a
    sub with () you always set @_ to the arg list or empty if no args. when
    you call with &foo, @_ is LEFT AS IS and that is seen by the called
    sub. that is a major difference and nasty if you don't expect it. so
    using () is the proper way to call subs in ALL cases unless you must use
    the & semantic (which is very very rarely needed). there is no other
    defensible reason to use & style calls in perl.

    uri
     
    Uri Guttman, May 19, 2009
    #6
  7. I'd say it is exactly these properties that make & "a thing of the
    past". In modern perl-code you don't want to do these things (well,
    almost never).

    There is one place where you still need the ampersand - if you need to
    take a reference to a sub. You cannot write

    sub foo {
    ...
    }

    my $x = \foo;

    you need to write

    my $x = \&foo;

    (otherwise foo will be called and $x will get a reference to its return
    value).

    hp
     
    Peter J. Holzer, May 19, 2009
    #7
  8. Guy

    Uri Guttman Guest

    PJH> There is one place where you still need the ampersand - if you
    PJH> need to take a reference to a sub.

    PJH> my $x = \&foo;

    also with magic goto you need the & prefix. and it leaves @_ as is which
    is an important part of its semantics of replacing the current sub with
    another. we never said & was not needed in perl, it is just not needed
    nor generally wanted in directly calling subs. when i see & for sub
    calls it raises a red flag and it usually means the rest of the code is
    on the poor side.

    uri
     
    Uri Guttman, May 19, 2009
    #8
  9. That's because (as Tad explained earlier) you are calling it with an
    argument list, i.e. with paranthesis. If you omit the paranthesis then
    you will get an error about bareword not allowed.
    Uri already explained that part.

    jue
     
    Jürgen Exner, May 19, 2009
    #9
  10. Yes, magic goto was one of the reasons why I qualified "you don't want
    to do that" with "almost never".
    who is "we"? And anyway, I didn't say that you said that, quite the
    contrary. To me, Jürgens claim that "& is not a thing of the past"
    implied that & *is* regularly needed in Perl for supressing prototypes
    and preserving @_. I stronglly disagree with that (and I don't actually
    think Jürgen meant that), so I wrote that you usually *don't* want to do
    these things.
    I fully agree with that.

    hp
     
    Peter J. Holzer, May 19, 2009
    #10

  11. There *are no* function declarations in your code.

    There are only function definitions.

    "define" and "declare" mean very different things!


    That is because you *pass* its contents to func2.

    func1's @_ is NOT visible to func2. func2 has a *different* @_.


    ----------------
    #!/usr/bin/perl
    use warnings;
    use strict;

    func1(1,2,3);

    sub func1 {
    &func2;
    }

    sub func2 {
    print "$_\n" for @_;
    }
     
    Tad J McClellan, May 19, 2009
    #11
  12. Guy

    News123 Guest

    Thanks for your explanations Uri and Juergen.


    As you said I misunderstood the term 'visible' and I
    always called own functions with '()', so never fell
    into the problem of calling a sub before its declaration

    For 99% of perl code I would give following advise:

    Don't use ampersand for calling functions
    Don't use function prototypes
    Don't declare functions separately before their definition.
    Group your function definitions either roughly bottom up at the
    beginning of your script or group them all top down at the end of your
    script.
    In the latter case I'd suggest an explicit exit() statement before the
    function definitions in order to signal to a person reading the code,
    that no more code outside of function definitions will follow (except of
    course for potential BEGIN blocks)

    bye
     
    News123, May 20, 2009
    #12
  13. Guy

    brian d foy Guest

    That's why we still talk about the & in Learning Perl. It makes the sub
    look more like what people already know about the other variable types.
     
    brian d foy, May 20, 2009
    #13
  14. Guy

    brian d foy Guest

    Remember that Learning Perl purposedly ignores a lot of details so you
    can get started as a Perl programmer a lot sooner than you would if you
    have to digest all of the Perl documentation.

    The leading ampersand on subroutine names is a first-week beginner
    thing before you've gone through perlfunc to see what Perl already
    defines. Often our students will redefine built-ins (log is a favorite)
    during their first couple of days of Perl.
     
    brian d foy, May 20, 2009
    #14
  15. body { font: Helvetica, Arial, sans-serif; } p { font: Helvetica, Arial, sans-serif; } ..standout { font-family: verdana, arial, sans-serif; font-size: 12px; color: #993333; line-height: 13px; font-weight: bold; margin-bottom: 10px; } ..code { border-top: 1px solid #ddd; border-left: 1px solid #ddd; border-right: 2px solid #000; border-bottom: 2px solid #000; padding: 10px; margin-top: 5px; margin-left: 5%; margin-right: 5%; background: #ffffea; color: black; -moz-border-radius: 10px; } ..codedark { border-top: 10px solid #03f; border-left: 1px solid #ddd; border-right: 2px solid grey; border-bottom: 2px solid grey; padding: 10px; margin-top: 5px; margin-left: 5%; margin-right: 5%; background: black; color: yellow; -moz-border-radius: 10px; } #code { color: black; font-size: 14px; font-family: courier; padding-left: 5px; } #line-number { color: #804000; font-family: Arial; font-size: 14px; padding-right: 5px; border-right: 1px dotted #804000; } blockquote[type=cite] { padding: 0em .5em .5em .5em !important; border-right: 2px solid blue !important; border-left: 2px solid blue !important; } blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid maroon !important; border-left: 2px solid maroon !important; } blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid teal !important; border-left: 2px solid teal !important; } blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid purple !important; border-left: 2px solid purple !important; } blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid green !important; border-left: 2px solid green !important; } News123 wrote: Don't use function prototypes
    I've heard that function prototypes don't always work - yet I find them useful. Where do they fail?
    Don't declare functions separately before their definition.
    Needed for recursive functions if you use prototypes.
    Group your function definitions either roughly bottom up at the beginning of your script or group them all top down at the end of your script.
    I fail to find the wisdom in putting all your functions at the bottom and push "main" to the top. IMHO well written scripts usually don't have exciting mains or if they do, they generally are "well worn" and thus usually not the part of the script that you, as a modifier, are generally interested in.
     
    Andrew DeFaria, May 20, 2009
    #15
  16. Guy

    Uri Guttman Guest

    SP> If you're communicating to a person, comments are far clearer:

    SP> # End main code body
    SP> # Function definitions follow

    SP> Use exit() for its intended purpose, explicitly returning an exit code
    SP> to the parent process.

    i disagree. in my top level programs i always put an explicit exit()
    after the main line code ends. comments can lie and there could be left
    over code below that would execute that shouldn't. i teach this style
    for top level programs:

    * a small number of key lexical declarations
    * up to about 5 or so top level sub calls (maybe storing results
    in lexicals)
    * then exit().

    if you start getting too many top level calls, refactor some into
    another call and move that sub after the exit.

    other layout points include putting arg parsing, usage and similar
    support subs at the very bottom where they are out of the way. put the
    subs in a general top down calling order (need not to be
    perfect). higher level subs can be followed immediately but some subs
    they call. of course, keep sub sizes reasonably small so you can
    understand them quickly.

    this makes for an easy to read and understand program.

    uri
     
    Uri Guttman, May 20, 2009
    #16
  17. RedGrittyBrick, May 20, 2009
    #17
  18. Guy

    Nathan Keel Guest

    If it's Perl code you're talking about, why not use something better
    suited for that, if you might have code/routines/comments that could
    create problems? exit() isn't the best method for preventing that
    problem, as much as I agree that it's not a bad idea for the same
    reasons, exit() isn't what I'd suggest.
     
    Nathan Keel, May 21, 2009
    #18
  19. Guy

    Uri Guttman Guest

    NK> If it's Perl code you're talking about, why not use something
    NK> better suited for that, if you might have code/routines/comments
    NK> that could create problems? exit() isn't the best method for
    NK> preventing that problem, as much as I agree that it's not a bad
    NK> idea for the same reasons, exit() isn't what I'd suggest.

    huh?? use what is better? exit is to exit and also tell the reader than
    no more main line code will be executed. it serves a dual purpose. not
    much else can do that.

    uri
     
    Uri Guttman, May 21, 2009
    #19
  20. body { font: Helvetica, Arial, sans-serif; } p { font: Helvetica, Arial, sans-serif; } ..standout { font-family: verdana, arial, sans-serif; font-size: 12px; color: #993333; line-height: 13px; font-weight: bold; margin-bottom: 10px; } ..code { border-top: 1px solid #ddd; border-left: 1px solid #ddd; border-right: 2px solid #000; border-bottom: 2px solid #000; padding: 10px; margin-top: 5px; margin-left: 5%; margin-right: 5%; background: #ffffea; color: black; -moz-border-radius: 10px; } ..codedark { border-top: 10px solid #03f; border-left: 1px solid #ddd; border-right: 2px solid grey; border-bottom: 2px solid grey; padding: 10px; margin-top: 5px; margin-left: 5%; margin-right: 5%; background: black; color: yellow; -moz-border-radius: 10px; } #code { color: black; font-size: 14px; font-family: courier; padding-left: 5px; } #line-number { color: #804000; font-family: Arial; font-size: 14px; padding-right: 5px; border-right: 1px dotted #804000; } blockquote[type=cite] { padding: 0em .5em .5em .5em !important; border-right: 2px solid blue !important; border-left: 2px solid blue !important; } blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid maroon !important; border-left: 2px solid maroon !important; } blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid teal !important; border-left: 2px solid teal !important; } blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid purple !important; border-left: 2px solid purple !important; } blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid green !important; border-left: 2px solid green !important; } RedGrittyBrick wrote:
    Andrew DeFaria wrote:

    I've heard that function prototypes don't always work - yet I find them useful. Where do they fail?

    If you haven't already read Tom's article[1], you might find it of interest.

    [1] http://groups.google.com/group/comp.lang.perl.modules/msg/84484de5eb01085b

    Well I've just read some, but not all - it's quite long. Tom's essential point seems to be "function prototypes are not flawless". Yeah, neither is Perl's current implementation of OO. However I still find both useful.
     
    Andrew DeFaria, May 21, 2009
    #20
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.