doran has asked for the wisdom of the Perl Monks concerning the following question:

Given a reference to a subroutine:

my $thingy = sub {print "Hola Mundo!\n"};

Is there an advantage one way or the other if I dereference the sub by $thingy->() vs. &$thingy ?

I prefer the former, since that's the way I'm used to dereferencing other things. But just about all examples I see use the '&' prefix instead of the arrow operator.

I'm just wondering if there are times when one way is better than the other.

Replies are listed 'Best First'.
Re: Dereferencing code refs with & vs. ->()
by merlyn (Sage) on Sep 22, 2005 at 23:44 UTC
    The arrow form wasn't added until 5.004, between release-candidate-1 and release-candidate-2, on a bet. And I won the bet.

    So, if you're looking at ancient documentation, you'll see &$coderef instead of the modern arrow form.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      Haha, that's hilarious. I'm glad you won. :)
Re: Dereferencing code refs with & vs. ->()
by jkeenan1 (Deacon) on Sep 23, 2005 at 01:07 UTC
    doran wrote:

    I prefer the former, since that's the way I'm used to dereferencing other things.

    Yes, you and most everybody else. I've rarely seen the & version in the last five years.

    But just about all examples I see use the '&' prefix instead of the arrow operator.

    Really? Where are those examples? In books dating from 1998?

    FWIW, TheDamian recommends the arrow form in Perl Best Practices. So, if nothing else, lots of other Perl programmers will understand what you're doing.

    And that's what's most important.

    Jim Keenan

      Really? Where are those examples? In books dating from 1998?
      Ummm, 1997 edition of the Panther book actually. :)

      It does mention the $thingy->() way of doing it, but all the other examples are the 'ol &$thingy way.

Re: Dereferencing code refs with & vs. ->()
by Fletch (Bishop) on Sep 23, 2005 at 02:30 UTC

    About the only place you'd need the ampersand version is if you're trying to get the current scope's @_ passed a la &somesub;. But that's really rare.

      Or anytime you're talking about a named subroutine (my $bar = \&foo;) or using the GOTO &SUB form (goto &$bar;). There's still a few places that it's required. Another reason to use the ampersand version is to disable prototype checking, for those subroutines that are evil enough to use it without good reason.

      My criteria for good software:
      1. Does it work?
      2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
        The use of &foo in \&foo has nothing to do with dereferencing. You're not calling foo.

        Also, in goto &$bar; you aren't derefencing - it's the magical goto that jumps to the subroutine pointed to by $bar. If you were derefencing, you'd jump to the label that was returned by &$bar;. And that's what's happening if you do goto $bar->();. Or goto &$bar();.

        Another reason to use the ampersand version is to disable prototype checking, for those subroutines that are evil enough to use it without good reason.

        But that's a difference between foo() and &foo(). Again, that has nothing to do with dereferencing. It can't even do prototype checking when doing dereferencing, as prototype checking is done at compile time. The following code runs without errors - despite violent prototype violations:

        !/usr/bin/perl use strict; use warnings; my $ref = sub ($) {print "Hello, world\n"}; &$ref(); $ref->(); __END__
        Neither the &$ref();, nor the $ref->(); is checked for its prototype.
Re: Dereferencing code refs with & vs. ->()
by ambrus (Abbot) on Sep 23, 2005 at 15:48 UTC

    I think it's mostly a question of style.

    The &-thingy has the disadvantage that beginners leave out the parentheses and wonder why the subroutine gets the arguments of its parents; otoh this is an advantage too, because you can't do the same with the arrow notation (and you can't do goto &$sub with arrows either). The arrow notation can sometimes be shorter, because you may not need the braces around an expression, or you might even leave out the arrow in newer versions of perl, for example:

    perl -we '$op{"+"} = sub { $_[0] + $_[1] }; $op{"-"} = sub { $_[0] - $ +_[1] }; print $op{$ARGV[1]}($ARGV[0], $ARGV[2]), $/;' 8 - 2
    Otoh, when you do need parentheses around the expression generating the function, the ampersand-notation is shorter.

    Other than these minor points, the difference is aesthetiyc. I always use the ampersand notation, moreover, I never use the arrow for dereferencing either an array or a hash or a code. I do use the arrow for method calls of course. (This style is new, it wasn't like this in my earlier scripts.)

Re: Dereferencing code refs with & vs. ->()
by pg (Canon) on Sep 23, 2005 at 01:12 UTC
    "I prefer the former, since that's the way I'm used to dereferencing other things."

    You don't actually use -> to de-referencing, you use it to access a member of a collection. When you dereference a hash or an array, you will use @ and %. In this sense, &$thingy holds more consistancy there.

    -> fits well with class method, as class can be viewed as a collection of properties and methods.

      You don't actually use -> to de-referencing, you use it access a member of a collection.

      No, you use {} and [] to access a member of a collection. You use -> to dereference references. That's why it is called a "dereference operator" in perlop. (Specifically, it's called an "infix dereference operator" which helps to describe the syntax.)

      Update: I imagine your confusion stems from the fact that it must be used in conjunction with {}, [], or () in order to be useful. (Hence "infix" btw.) Still, it's doing the same job as the leading dollar sign ($) in $$thingy[0].

      -sauoq
      "My two cents aren't worth a dime.";
      
Re: Dereferencing code refs with & vs. ->()
by Anonymous Monk on Sep 23, 2005 at 09:08 UTC
    To address the actual question, the advantage of using $ref -> () instead of &$ref() is that the former obeys the strict references pragma and the latter will generate an error when using strict references.
      (oops forgot to log in when posting the above)

      Update: Actually it is more complicated than that - I should have inserted a qualifying clause rather than implying this is true for all cases, but alas I did not post it under this account and can't update it anymore.

      -M

      Free your mind

      Bullshit.
      #!/usr/bin/perl use strict; use warnings; my $ref = sub {print "Hello, world\n"}; $ref->(); &$ref(); # Look ma, I am using strict! __END__ Hello, world Hello, world
      But:
      #!/usr/bin/perl use strict; use warnings; sub hello {print "Hello, world\n"}; my $ref = "hello"; $ref->(); __END__ Can't use string ("hello") as a subroutine ref while "strict refs" in +use

        Maybe you could have said something more civil than "bullshit"? Politeness is free, and the payback is large, try it, you might like it.

        ---
        $world=~s/war/peace/g

        A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Dereferencing code refs with & vs. ->()
by Anonymous Monk on Sep 23, 2005 at 10:08 UTC
    I prefer &$thingy over $thingy->(). It's one character less (three less if you're not passing arguments), and it's more general. This works:
    &{ Block returning a code reference }
    but this doesn't:
    { Block returning a code reference }->();

    That's why I also prefer:

    $$hash_ref{key} = $$array_ref[1];
    over
    $hash_ref->{key} = $array_ref->[1];
    -> is not a shortcut. It's a detour ;-)

      I prefer &$thingy over $thingy->().

      Aren't these apples and oranges?

      sub t { my $sub=shift; $sub->(); } sub u { my $sub=shift; &$sub; } t(sub{print">@_<"},1,2,3,4,5); u(sub{print">@_<"},1,2,3,4,5); _END__ >< >1 2 3 4 5<

      It's one character less (three less if you're not passing arguments), and it's more general.

      More general? Im not sure I agree with that... And im not convinced about the one character less either. Id say that for the below its actually one character more. Especially given the above point that &{EXPR}() is the equivelent of EXPR->() and not &{EXPR}

      do { sub { print 'foo' } }->(); ( sub { print 'bar' } )->();

      That's why I also prefer:$$hash_ref{key} = $$array_ref[1];

      I class that notational style as a code smell. If I have to deal with code like that the first thing I do is switch it to use the infix dereference operator. And strangely I often find that the bug I was looking for just vanishes by doing so. IOW: this style is error prone and IMO a maintenance nightmare.

      ---
      $world=~s/war/peace/g

      &{ Block returning a code reference }

      Are you saying that your code is littered with

      &{do { # stuff here sub { ... }; }};
      Because I'm not sure I like that syntax. It looks very obfuscated, to my eyes.

      $$hash_ref{key} = $$array_ref[1];

      Yes, I see that a lot in older code. The problem is that this syntax only works because of how tightly $ binds vs. {} or []. You're depending on the Perl parser always guessing correctly. Maybe I'm paranoid, but I prefer not making the parser guess my intention.


      My criteria for good software:
      1. Does it work?
      2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
        The official way of coding that is:
        ${$hash_ref}{key} = ${$array_ref}[1];
        You may leave of the braces if the content of the block is a simple variable. Perhaps you find that obfuscated, but that's actually the same rule as the first (optional) argument of print. The file handle is passed as a block, and taken as the result, but if the block is a simple variable, you may leave off the braces. If that isn't obfuscated, why is the code I presented obfuscated? Or is it that you aren't used to it, and call anything you aren't used to obfuscated?

        If you want to take a slice of a hash or an array, and all you have is a reference to it, how do you do it without being "obfuscated"? I write it as:

        @$hash_ref{$key1, $key2, $key3};
        which follows naturally from accessing a single value:
        $$hash_ref{$key1};
        But
        @hash_ref->{$key1, $key2, $key3};
        doesn't work and nor does
        $hash_ref->{$key1, $key2, $key3};

        And no, my code isn't littered with

        &{do {... sub {...}}};

      { Block returning a code reference }->(); doesn't work, but ( Block returning a code reference )->(); works, doesn't it?

      Also &$thingy calls the subroutine with the same @_, so it's not the same as $thingy->(), this latter is really equivalent to &$thingy(). I think you probably thought of &$thingy() anyway, as that's what's one character less than $thingy->().