Search code examples
perlreferenceanonymous-methods

Deferencing a subroutine syntax


I would like to know why the following syntax fails

 #!/usr/bin/env perl

use warnings;
use strict;

sub add { return $_[0]+5; };
my $add_ref = \&add;

my $result = 0;

$result = &add(5);
print " result is $result \n";

$result = add(5);
print " result is $result \n";

#$result = $add_ref(5);  ---------------> fail
#print " result is $result \n";

#$result = {$add_ref}(5); -----------------> fail
#print " result is $result \n";

$result =  &{$add_ref}(5);
print " result is $result \n";

$result =  $add_ref->(5);
print " result is $result \n";

1) I have just replaced the name of function add with {$add_ref} which is the method referred in Intermediate Perl book. In a function call & is optional, but why not in this case.

2) I also find that $reference_to_anonymous_subroutine(parameter) works but not $reference_to_names_subroutine(parameter)

Example

my @array = (1, sub { my $n = $_[0]; $n = $n +5;});

my $result = $array[1](2); ---------> works and does not need &{$array[1]}(2)
print "$result \n"; 

Solution

  • The problem is that Perl has to make a reliable guess about what you mean.

    Given this definition of $add_ref

    sub add { return $_[0]+5; };
    my $add_ref = \&add;
    

    the "proper" way to call the subroutine would be to use the indirection operator -> which implcitly dereferences its left operand (in a similar way to the "fat comma" => implicitly quoting its left operand).

    So you could write the dereference explicitly as

    &$add_ref(5)
    

    or do it implicitly with

    $add_ref->(5)
    

    Perl always works very hard to work out what you mean by what you write, so I am sure that resolving your statement

    $result = $add_ref(5)  # Syntax error
    

    as an indirect subroutine call would have caused a problem with ambiguity.

    It is much clearer with your second statement

    $result = {$add_ref}(5)  # Syntax error
    

    which which is a syntax error because a bare block can't return a value. (In fact you are declaring an anonymous hash with a single key and no value, and then trying to call it.) If you use do, and the indirection operator then everything is fine. Like this

    $result = do{$add_ref}->(5)
    

    but I wouldn't recommend it. Or you could put the block in context, as you did with your next example, and write

    $result = &{$add_ref}(5)
    

    which, because the dereference happens first, is identical to

    $result = &$add_ref(5)
    

    While Perl references may seem confusing, it will become clearer as you get used to the language. Because of the author Larry Wall's background in linguistics it works very much like a very formal natural language. In every spoken language there are endless "irregular" words, and they have developed that way because the people who use them find it most convenient. There is no other "why", but it is a reason why programmers who have spent less thah a couple months with Perl will quickly denounce it as obscure.