http://www.perlmonks.org?node_id=999996

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

Guys, this is not a big deal, but I cannot decide which is best. You know, I just want to be consistent in my code and when it comes to calling a subroutine from a reference, I have basically two options. Either:

As of now, I have always used the first one, but I think the second is more elegant, but at the same time could be confusing. What do you guys think?

There are no stupid questions, but there are a lot of inquisitive idiots.

Replies are listed 'Best First'.
Re: How to call a sub-routine ref
by moritz (Cardinal) on Oct 19, 2012 at 17:55 UTC

      Imagine this:

      &{$hashref->{'key'}}('key');

      vs.

      $hashref->{'key'}->('key');

      Don't you think the second could lead to confusions?

      I'm just trying to find what is best, I honestly prefer the first but I've never seen it until recently, so I am thinking maybe no one uses it because it may be harder to understand at first sight.

      There are no stupid questions, but there are a lot of inquisitive idiots.

        greengaroo:

        Odd, I find your examples a good case for using the second one. Again, different people will find different things more clear.

        When I use hashes, I generally use $$h{foo} in preference to $h->{foo}, primarily because it's easier to type, and I use hashes quite a bit. If I were trying to make it visually distinctive, I'd make the harder to type one be for the less frequently used case. Thus, I'd use something like:

        $$hashref{key}->('arg');

        To my eye, that stands out better. (But with my luck, it would blow up, so I'd better whip up a test...)

        $ cat t.pl use strict; use warnings; sub p { print "foo(", join(", ", @_), ")\n"; } my $hr = { key=>\&p }; $$hr{key}->('arg'); $ perl t.pl foo(arg)

        ...roboticus

        When your only tool is a hammer, all problems look like your thumb.

        For that particular case, you don't need either the -> or the &{}:

        sub x{ say "x got [ @_ ]"; };; $h{x} = \&x;; $href = \%h;; $href->{x}('fred','bill');; x got [ fred bill ]

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        RIP Neil Armstrong

        I find the first one much harder to read. The difference between ( and { is subtle, but properly named variables ($handlers->{$event_name}->($event)) would make that irrelevant.
Re: How to call a sub-routine ref
by tobyink (Canon) on Oct 19, 2012 at 22:04 UTC

    I've got some more candidates for you...

    • ()->$ref;
    • do{}->$ref;
    • ()->$ref();
    • do{}->$ref();

    These are all variations on the method call syntax.

    Also, very deprecated...

    • no warnings; do $ref();
    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
      Wow, that looks like magic. Can you please describe why those lines work at all? Or where in perl docs is it explained?

        See the documentation on the arrow operator in perlop.

        Otherwise, the right side is a method name or a simple scalar variable containing either the method name or a subroutine reference, and the left side must be either an object (a blessed reference) or a class name (that is, a package name). See perlobj.

        In the examples, all things on the left hand side return undef, and Perl will call that subroutine reference with the return value. The documentation could be a bit more clear about that undef will also "trigger" that case.

        use strict; use Data::Dumper; my $ref = sub { print Dumper \@_ }; ()->$ref; do{}->$ref; ()->$ref(); do{}->$ref(); __END__ $VAR1 = [ undef ]; $VAR1 = [ undef ]; $VAR1 = [ undef ]; $VAR1 = [ undef ];
        use v5.14; use JSON -convert_blessed_universally; use Test::More; package Foo { sub new { bless \@_ => shift } sub bar { return JSON::to_json(\@_, { convert_blessed => 1, canoni +cal => 1 }) } } package Oof { our @ISA = 'Foo'; sub bar { scalar reverse JSON::to_json(\@_, { convert_blessed => 1 +, canonical => 1 }) } } # You are no doubt familiar with these... my $obj = Foo->new(1); # calling a class method (a constructor) my $str = $obj->bar; # calling an object method is($str, '[[1]]', 'bar returned what we expected'); # Did you know you could do this? my $constructor = 'new'; my $method = 'bar'; $obj = Foo->$constructor(1); $str = $obj->$method; is($str, '[[1]]', 'bar returned what we expected'); # We can even use fully qualified names... $constructor = 'Foo::new'; $method = 'Oof::bar'; $obj = Foo->$constructor(1); $str = $obj->$method; is($str, ']]1[[', 'Oof::bar is the stringy reverse of Foo::bar'); # Or we can use coderefs $constructor = \&Foo::new; $method = \&Oof::bar; $obj = Foo->$constructor(1); $str = $obj->$method; is($str, ']]1[[', 'Oof::bar is the stringy reverse of Foo::bar'); # Now, what is the point of blessing things? We bless objects # so that when we call $object->method, Perl "knows" what # package to find the method in. # # But if we can use coderefs as if they were methods, then # Perl doesn't really need the object to be blessed... # $method = \&Oof::bar; $obj = [1, 2, 3]; # a plain arrayref $str = $obj->$method; is($str, ']]3,2,1[[', 'Can call coderef methods on unblessed things'); # It even works with undef $method = \&Oof::bar; $obj = undef; $str = $obj->$method; is($str, ']llun[', 'llun is null backwards'); # A pair of parentheses evaluates the empty list in list # context, but undef in scalar context. The arrow operator # imposes a scalar context on the left-hand side. $method = \&Oof::bar; $str = ()->$method; is($str, ']llun[', 'llun is null backwards'); # do{} with nothing inside the block returns undef $method = \&Oof::bar; $str = do{}->$method; is($str, ']llun[', 'llun is null backwards'); # More fun... $method = \&Foo::bar; $str = do { my $x = 1; my $y = 2; $x+$y }->$method(2,1); is($str, '[3,2,1]', 'more fun'); # This makes sense when you consider what comma does in scalar context +... $method = \&Foo::bar; $str = (5,4,3)->$method(2,1); is($str, '[3,2,1]', 'maybe counter-intuitive'); done_testing();
        perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: How to call a sub-routine ref
by Kenosis (Priest) on Oct 19, 2012 at 18:33 UTC

    I prefer the arrow operator since it provides a nice, overt dereferencing visual suggesting it's pointing or referring to something else.

      And if you don't have an argument to pass, isn't it weird to have empty parenthesis?

      $hashref->{'key'}->();

      There are no stupid questions, but there are a lot of inquisitive idiots.
        Why would it be weird? Parens around the arg list, even an empty args list, is the normal way of calling a sub. Omitting parens leads to many problems.

        greengaroo:

        As a long-time C/C++/C# coder, I don't find the empty parenthesis weird. (Though it took me a (very) little while getting used to leaving off parenthesis altogether.)

        ...roboticus

        When your only tool is a hammer, all problems look like your thumb.

Re: How to call a sub-routine ref
by blue_cowdawg (Monsignor) on Oct 19, 2012 at 18:34 UTC
        alling a subroutine from a reference

    assuming for a second you are talking about a reference such as

    | stuff before my $sref = \&foo | stuff after
    then you would call it thusly:
    | later &($sref)( arg1....argn); |
    where "arg1...argn" would be replaced by the arguments you want passed to the sub.

    Here is a more complete example:

    #!/usr/bin/perl -w use strict; my $sref=\&foo; &{$sref}; exit(0); sub foo { print "This is foo.\n"; }


    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg

      Yes I know. Here is another example with an anonymous subroutine:

      my $ref = sub { print "Hello World!\n"; }; # Both are equivalent $ref->(); &{$ref}(); # But which one is best? That is the question!

      Also, I don't do simple stuff like that, I have objects and callback functions and so on. Most of the time I have deep structures that returns functions, or objects, then I want to call that function or object method.

      Let me sleep on it and I will try to provide a more concrete example.

      There are no stupid questions, but there are a lot of inquisitive idiots.

        Did you actually test that code?

        $ cat greengaroo.pl use strict; my $ref = sub { print "Hello World!\n"; }; # Both are equivalent $ref->(); &{ref}(); # But which one is best? That is the question! $ perl greengaroo.pl Hello World! Undefined subroutine &main::ref called at greengaroo.pl line 9.

        your second call fails.

        If you fix this by rewriting it thusly:

        &{$ref}();
        there is still the open question of "which is better?" From a readability standpoint I'd vote for the latter rather than the former. Others may disagree but that is the essence of TIMTOWTDI. If you feel there may be a performance issue involved here have you tried profiling the code?


        Peter L. Berghold -- Unix Professional
        Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg
Re: How to call a sub-routine ref
by PrakashK (Pilgrim) on Oct 19, 2012 at 18:43 UTC

    Is the first one even correct? I get the Useless use of private variable in void context warning, when warnings are enabled.

    Or, did you mean to say:

    &$ref();

    I prefer the second one, as it feels more consistent with the way the other references are used as well:

    $aref->[...]; # as opposed to @$ref[...] $href->{...}; # as opposed to %$ref{...}

      You are right, I forgot the "&". Fixed.

      And I agree with what you are saying.

      There are no stupid questions, but there are a lot of inquisitive idiots.
Re: How to call a sub-routine ref
by Anonymous Monk on Oct 19, 2012 at 18:42 UTC
    "Be consistent in your code." Full stop.

      Of course I want my sauce to be consistent, but sometimes I find new spices and I want to change the recipe! Don't worry, it will be consistent, I promise!

      There are no stupid questions, but there are a lot of inquisitive idiots.