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

I was working on some code that called a subroutine stored in a hash. But it wouldn't compile under strict until I added another set of curly braces. My question is, why?
use strict; sub test { print 'hello world!' }; my %hash; $hash{test} = \&test; # This generates an error: &$hash{test}; # Global symbol "$hash" requires explicit package name at script.pl li +ne 7. # syntax error at script.pl line 7, near "$hash{test" # Execution of script.pl aborted due to compilation errors. # But this works: &{$hash{test}}; # why???

Replies are listed 'Best First'.
RE: hash o' refs
by merlyn (Sage) on Aug 08, 2000 at 02:42 UTC
    Why? Because that's the right syntax. The canonical invocation of a coderef is:
    &{ THING_THAT_CONTAINS_A_CODE_REF }( @ARGS ) # (@ARGS) optional
    Which would be your final line. You may drop the curly braces around THING_THAT_CONTAINS_A_CODE_REF if and only if the THING is a simple scalar variable. Yours is not.

    As an alternative syntax, you may use

    THING_THAT_CONTAINS_A_CODE_REF -> ( @ARGS )
    which would be
    $hash{test}->()
    in your case. That last syntax is due to yours truly challenging chip to get it in during the final perl 5.004 gamma release, which he did. You're welcome. {grin}

    -- Randal L. Schwartz, Perl hacker

      I am about to give this syntax the highest praise I can imagine:
      "Of course you can do that, how else would it work?"

      /me can think of no better compliment to any software feature.

      Russ
      Brainbench 'Most Valuable Professional' for Perl

      And I thank you!

      $hash{test}->();
      Looks a lot better then:
      &{$hash{test}}();

RE: hash o' refs
by mwp (Hermit) on Aug 08, 2000 at 02:48 UTC

    As chip pointed out to me at one point, & is trying to use $hash as a code reference, and not looking at the full $hash{test} to get the desired result. The braces explicitly define the coderef to be evaluated.

    I always use braces to dereference things as a general rule. It's easier to read and helps avoid problems like the above :-) I've also found that this is a nice way to work with code refs (and any ref in general):

    $dog = $hash_ref->{dog}; $apple = $ary_ref->[3]; $car = $code_ref->('Ford');

    A quick $hash{test}->(..params..) should do the trick, since the arrow operator is smarter (a more flexible binder) than '&'. You may or may not find it easier to read than &{$hash{test}}(..params..).

    Alakaboo

    (UPDATE: Ugh, both merlyn and tilly beat me to the punch. Drat!!)

Re: hash o' refs
by tilly (Archbishop) on Aug 08, 2000 at 02:46 UTC
    The problem is that you misunderstand how Perl parses your code. When you write &$hash{test} Perl treats that as {&$hash}{test}, $hash has not been declared, and strict informs you of that. But by adding the braces where you intended them to go you force Perl to behave as you thought it should, and it works.

    Incidentally this is a case where you should send merlyn a note of personal thanks for thinking up the very nice piece of syntactic sugar: $hash{test}->();

RE: hash o' refs
by Anonymous Monk on Aug 08, 2000 at 18:42 UTC
    I have a question. If I have an object "foo" with a method "color" which returns a reference to a hash within foo that store's color I could use it in the following manner:

    print "A foo is ".$foo->color.". Isn't that pretty?\n";
    and get for example,

    A foo is blue. Isn't that pretty?

    But if I use:
    print "A foo is $foo->color . Isn't that pretty?\n";

    or if I use:

    print "A foo is ${$foo->color}. Isn't that pretty\n";

    Perl returns hash references literally.
    I can understand why it would do that for the first item but why can't ${$foo->color} be evaluated within a string?
      You can't call a method as a double-quoted string interpolation. You can use a hashref or arrayref, or a simple array or hash element, or an array slice or hash slice, or a simple scalar. Isn't that enough? {grin}

      But apparently, a method call was considered too much like a full expression to be parseable, er, possible inside a double-quoted string.

      -- Randal L. Schwartz, Perl hacker