Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

What's so bad about &function(...)?

by japhy (Canon)
on Dec 07, 2005 at 18:01 UTC ( [id://514943]=perlmeditation: print w/replies, xml ) Need Help??

On IRC and here at perlmonks, I often see people get "corrected" when they call their functions (theirs, not Perl's built-in functions) with a leading ampersand. I'm not talking about using &foo, I'm talking about using &foo(...).

What's the problem? I don't believe people are really concerned that these beginners are avoiding the prototypes of their functions, because 95% of the time, I also hear "don't use prototypes". So what's the problem with calling user-defined subroutines with an ampersand? Yes, it's optional, but it's not detrimental.


Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart

Replies are listed 'Best First'.
Re: What's so bad about &function(...)?
by tirwhan (Abbot) on Dec 07, 2005 at 18:16 UTC

    (As read in Perl Best Practices): The ampersand is ambiguous and can be interpreted by perl as bitwise AND in certain contexts. Since it is not necessary, it is better to always omit the &.


    Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. -- Brian W. Kernighan
      The ampersand is ambiguous and can be interpreted by perl as bitwise AND in certain contexts.

      Wow, I've never seen that trap sprung.

      The trap I have seen sprung quite a few times is sub log { ... }. That is why I follow my own advice in my 'classic' node, (tye)Re: A question of style, and mix case in all of my subroutine names.

      But, I sometimes slip and use camelCase and then get lazy and give a routine or two one-word names and... I've actually still been bit by sub log { ... }, just less frequently than before.

      So using &func( ... ) is still in my list of optional best practices for two reasons. First, it prevents you from being caught (often very confusingly) if you unintentially give your subroutine a "reserved" name. Second, it is a valid style choice to visually distinguish user sub calls from other similar-looking constructs.

      Note that if you import a &log, then log() will call it and so the leading ampersand is not as useful for imported routines. So I don't find the "might disable prototypes" argument too worrisome. Since, if I didn't important the routine, then I'm sure to know whether or not I was stupid enough to use a prototype on it. While, if I imported the routine, I don't need to use the ampersand (and modules that export over the top of built-in functions usually have a good reason for doing so or get bug reports filed against them).

      Now, as far as best practices go, I consider "always mix case (or add an underscore) in your subroutine names" to be a better "best practices" then "use &sub(...) when calling your own subs", because there are fewer nearby potential down-sides (such as using &sub w/o parens). But I do get annoyed when I see (every time the subject comes up) a bunch of people spouting poorly justified proclamations against using &sub(...) while also not warning against using subroutine names that might accidentally match a built-in.

      - tye        

      The ampersand is ambiguous and can be interpreted by perl as bitwise AND in certain contexts. Since it is not necessary, it is better to always omit the &.
      Sounds profound, and it got you quite some XP. It should have been negative XP, because your conclusion is 100% wrong. If you you are afraid to get be bitten by the ambiguity you mention, you should avoid using bitwise and, not the sub-sigil. Because whenever perl has the option to parse an ampersand as a sub-sigil or as a bitwise and, it will parse it as the sub-sigil.
      $ perl -MO=Deparse,-p -e 'sub foo {} sub bar {} bar & foo()' sub foo { } sub bar { } bar(&foo()); -e syntax OK
      Someone using sub-sigils in the above case would have gotten the binary and parsing:
      perl -MO=Deparse,-p -e 'sub foo {} sub bar {} &bar & &foo()' sub foo { } sub bar { } (&bar & &foo());
      So, you have two options to avoid this ambiguity: either avoid using binary and, or to always use the sub-sigil.
      Perl --((8:>*
Re: What's so bad about &function(...)?
by Ovid (Cardinal) on Dec 07, 2005 at 18:15 UTC

    Because if beginnners are going to stick with simple code (which is fine) they should be sticking with simple code which doesn't run the risk of mysterious side effects (which is not fine).

    Cheers,
    Ovid

    New address of my CGI Course.

      What is the mysterious side effect of using a leading ampersand? The only side effect I can think of, off the top of my head, is that it avoids prototypes, and prototypes, I would expect, are outside the realm of "simple code".

      Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
      How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart

        Yes, but not everyone programs in a vacuum. Sooner or later they'll start using code which does have prototypes. Imagine, for example, that they start using Test::More. Those functions all have prototypes and using the leading ampersand is sure to bring them woe. Imagine, for example, typing "is" instead of "ok":

        &is(some_func(3,4));

        The prototype is now disabled so they don't get the compile-time failure telling them that the test function has been called incorrectly. If you're new to testing or that's buried in bunch of other tests, it can be quite difficult to figure out.

        Cheers,
        Ovid

        New address of my CGI Course.

        If you don't specify arguments, it passes any existing @_.
        #!/usr/bin/perl use strict; use warnings; yes_ampersand("yes\n"); no_ampersand("no\n"); sub foo { print $_[0]; } sub yes_ampersand { print $_[0]; &foo; } sub no_ampersand { print $_[0]; foo; }
        Here's the output:
        yes yes no Use of uninitialized value in print at ampersands.plx line 9.
        --
        Marvin Humphrey
        Rectangular Research ― http://www.rectangular.com
Re: What's so bad about &function(...)?
by Limbic~Region (Chancellor) on Dec 07, 2005 at 18:17 UTC
    japhy,
    I think it is half cargo-culting the mantra where the difference between &sub and &sub() is unknown by the chanter and half a good rule of thumb. You can't get bitten by a confusing @_ or circumvented prototype if you avoid using a preceding & all together.

    Cheers - L~R

Re: What's so bad about &function(...)?
by jdporter (Paladin) on Dec 07, 2005 at 18:32 UTC

    For the same reason we don't recommend writing @{\@foo} when @foo works just as well.

    :-)

    We're building the house of the future together.

      That reminds me of a question I like to use for teaching intermediate-level perlers:

      What is the difference between @{\@foo} and @{[@foo]}?
      I think it makes a good interview question, too.

      I don't think it is really the same reason at all. The reference/dereference cycle in your example is real, but insignificant, while the & sigil is usually optional but sometimes affects perl parsing and compilation. Ovid and tirwhan covered the traps nicely.

      After Compline,
      Zaxo

        I'll bite. The second makes a copy of the array, the first doesn't. Right...? I hope. Or I've embarrassed myself terribly.

        What is the difference between @{\@foo} and @{@foo}?

        Um... they're both the wrong way to write @foo, but the second one's more inefficient, but caring excessively about efficiency of bad code that you should refactor anyway is a premature optimization, so ... umm... it's a trick question, with the answer of "There's no difference; you'ld never use either one in production code?"

        Do I win? :-) Or did I miss something subtle? :-(

Re: What's so bad about &function(...)?
by revdiablo (Prior) on Dec 07, 2005 at 21:28 UTC

    My main objection is cosmetic. I think using the & is ugly. Specifically, I think it's yet another piece of unnecessary syntax. I try to minimize unnecessary syntax as much as possible. It's the same reason I omit parentheses under cases where they're not needed for either precedence or clarity.

      It's the same reason I omit parentheses under cases where they're not needed for either precedence or clarity.

      Then you're forcing the maintainers to memorize an operator precedence table to infer your meaning, instead of writing it explictly. At the time you write you code, you know exactly what you mean, and where the parens must go, but you then take away this information in order to promote "consiseness". This is, in my experience, where mistakes tend to happen. I don't think the risk is worth the gain.

      For one thing, I don't think it's worth it to do that much work in stripping down my code. Whenever I find that I've really got too many layers of parens, then I've always found that my code itself is too complex; so I simplify it, or break it into sub-expressions.

      For me, it's all about minimizing the time spent proving the code is correct; if I have to spend time pulling up an obscure table in my memory and cross checking it, there's a chance I'll fuck it up, especially if I'm sick, over-tired, or hungry. Worse yet, I have to carefully cross check code any code that doesn't include parens (and look up that damned table(!)), because I don't know if you were sick, tired, or hungry when you wrote the code, so I don't know if you intended the odd precedence the code may happen to be running with, or if it's a horrible mistake. An explict encoding (and decent comments!) correct both problems.

      Do whatever works best for you, but in my experience, minimizing the number of things I have to think about to get the code right leads to fewer mistakes, and fewer bugfixes six months after I've forgotten about the project and what it's all about.

      --
      Ytrew

        Then you're forcing the maintainers to memorize an operator precedence table to infer your meaning, instead of writing it explictly.

        Notice the word "clarity" in my original sentence. You seem to have missed it the first time through. Or maybe you just didn't understand what I meant. Statements where a maintainer is forced to memorize precedence tables are NOT clear, and hence fall under my "clarity" caveat.

Re: What's so bad about &function(...)?
by Roy Johnson (Monsignor) on Dec 07, 2005 at 21:45 UTC
    I think the reason they get corrected is that that's not what ampersand is for (any more). It's a little like the people who always stick variables in quotes. It suggests that you're doing something when you're not. It's code clutter.

    Caution: Contents may have been coded under pressure.
Re: What's so bad about &function(...)?
by zentara (Archbishop) on Dec 08, 2005 at 13:38 UTC
    It gets further complicated by the widely used references to subs, which contain ampersands, and is never critisized.
    $window->signal_connect( 'destroy' => \&delete_event );

    I'm not really a human, but I play one on earth. flash japh
      the widely used references to subs ... is never critisized

      That's not criticized because it's the only way to take a reference to a subroutine, short of pulling it out using the typeglob (which is even uglier).

Re: What's so bad about &function(...)?
by Siddartha (Curate) on Dec 09, 2005 at 17:03 UTC
    In the end it doesn't really matter. Like almost anything in Perl you can do it in more than one way. If you know the pitfalls with all the different options then good for you. Use whatever you want.
    The fact remains though that for someone new to Perl using &foo could pose a lot more problems than not using it, so to make it easier for beginners not to walk into problems they are not aware of, rather leave it out in the code submitted here.
    If they know enough about perl and read discussions like this one then they can decide to use whatever they want but be aware of the consequences.
    Just my opinion.
      Another reason it doesn't much matter is that, to make things more consistent, we're changing what it means in Perl 6. The notation no longer has anything to do with how the arguments are processed--there are now flattening operators for that. Instead, when you say &foo, you're explicitly marking "foo" as a noun rather than a verb. As a noun, it always returns a scalar reference in scalar context, and like any other reference, it is not dereferenced unless you do so explicitly. In the case of &foo, it is not called unless you say &foo() or some such.

      Interestingly, this completely removes the Perl 5 distinction between foo(1,2,3) and &foo(1,2,3). Those are handled identically in Perl 6. What changes is the meaning of bare &foo. You now always have to pass @_ explicitly if that's what you mean.

        In Perl5, if you have arguments to a function, the parenthesis are optional if you don't use the & sigil (unless of course they are needed to prevent misparsing). However, if you use &foo to call a sub, and you want to call it with arguments, the parenthesis are mandatory.

        Will you be able to do:

        &foo 1, 2, 3
        in Perl6?
        Perl --((8:>*

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://514943]
Approved by davidrw
Front-paged by Zaxo
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (7)
As of 2024-04-23 16:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found