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

Hi Monks,

to use a constant defined constant as a hash key it is a common notation to write $hash{+CONST}. But why does it not work if I use the '+' notation to literally specify a hash? Example:

use strict; use warnings; use Data::Dumper; $Data::Dumper::Sortkeys = 1; use constant FOO => 'the FOO key'; my %h1 = ( +FOO => "the value" , FOO_const => FOO); my %h2 = ( FOO , "the value", FOO => "other value"); # comma my @a = ( +FOO, FOO); print(Dumper(\%h1, \%h2, \@a), $h2{+FOO}, "\n");
This prints:
$VAR1 = { 'FOO' => 'the value', 'FOO_const' => 'the FOO key' }; $VAR2 = { 'FOO' => 'other value', 'the FOO key' => 'the value' }; $VAR3 = [ 'the FOO key', 'the FOO key' ]; the value
Surprisingly, the +FOO in the initialization of %h1 is turned to the string 'FOO'. Yes, i can use the standard comma or (FOO) =>... instead, but i would like to understand why the '+' notation does not work as expected when used left to a fat comma.

Replies are listed 'Best First'.
Re: Why is +CONST left to a fat comma not treated as in $hash{+CONST}?
by choroba (Cardinal) on Jan 05, 2024 at 12:01 UTC
    That's how the fat comma works: it turns the word to the left of itself into a string.
    $ perl -MO=Deparse,-p -Mstrict -e 'sub b;sub c;(1+b=>c)' sub b; use strict; ((1 + 'b'), c()); sub c;

    The behaviour can be sometimes surprising, but it's documented in perlop:

    The special quoting behavior ignores precedence, and hence may apply to part of the left operand:
    print time.shift => "bbb";
    That example prints something like "1314363215shiftbbb", because the => implicitly quotes the "shift" immediately on its left, ignoring the fact that "time.shift" is the entire left operand.

    Update: See also Using constants as hash keys.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      Thanks, i see.
Re: Why is +CONST left to a fat comma not treated as in $hash{+CONST}?
by ikegami (Patriarch) on Jan 05, 2024 at 15:42 UTC

    i would like to understand why the '+' notation does not work as expected

    unary-+ literally has no effect. It does nothing. It just returns the value provided to it.

    It's even transparent to context

    $ perl -Mv5.14 -e'my @a = qw( d e f ); say for +@a' d e f

    So why do we use it?

    Well, the Perl grammar has ambiguities. The same sequence of tokens could have two valid meanings. So Perl sometimes has to guess which meaning you mean. By inserting the do-nothing unary-+ in that sequence, we can sometimes create a sequence that's no longer ambiguous, or one that changes how Perl chooses to resolve the ambiguity.

    For example, the { in map { could be the start of a block or it could be the start of a hash constructor. This is an ambiguity. However, the { in map +{ can only be the start of a hash constructor. There is no ambiguity.

    So what about $hash{ +FOO }?

    $hash{ FOO } is ambiguous, except it's documented that Perl will auto-quote what's in the curlies if it's entirely an identifier. Therefore, this is treated as $hash{ "FOO" }.

    $hash{ +FOO } avoids that. Since the entirety of the contents of the curlies is no longer entirely an identifier, it's not auto-quoted, letting FOO have the same meaning it would have in my $key = FOO;.

    So what about +FOO => ...?

    => auto-quotes the identifier that precedes it, if any. With or without the +, FOO is still right before the => and thus gets treated as "FOO".