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

Hi,

I am confused by the following piece of code:
#!/usr/local/bin/perl -w use strict; use constant TESTVALUE => 1; my %hash1 = (TESTVALUE => "OK"); my %hash2 = (123 => TESTVALUE); my $hashValue; # Try 1 $hashValue = %hash1->{1}; # Try 2 $hashValue = %hash1->{TESTVALUE}; # Try 3 $hashValue = %hash1->{%hash2->{123}};
Only try 2 returns the desired result "OK" from hash1. Why not try 1 and try 3? Am I missing something?

TIA

Replies are listed 'Best First'.
Re: Hash values and constants
by ihb (Deacon) on Jan 12, 2003 at 15:28 UTC
    Good question.

    First a quick note: Although %hash->{key} works you shouldn't do that. $hash{key} is the right way to use a hash. This is a known bug.

    Anyhow, the problem boils down to that   $hash{KEY} is interpreted as   $hash{'KEY'} and that a bareword to the left of => also is interpreted as a string. So what you have is:
    my %hash1 = ('TESTVALUE', 'OK'); my %hash2 = (123, , 1);
    What you want to have is   my %hash1 = (TESTVALUE() => 'OK'); or   my %hash1 = (TESTVALUE, 'OK'); When getting the value with the constant you need to make it a non-bareword:   $hash1{+TESTVALUE} or   $hash1{TESTVALUE()} Update:
    I intentionally avoided mentioning & as a way of disambiguate the constant. This is because it will confuse and mislead people to think that you can do &foo; instead of foo(), which isn't the case. See perlfaq7.

    Hope I've helped,
    ihb
Re: Hash values and constants
by pfaut (Priest) on Jan 12, 2003 at 15:30 UTC

    From Programming Perl, pg. 108 under 'Comma Operator' (emphasis mine):

    The => digraph is mostly just a synonym for the comma operator. It's useful for documenting arguments that come in pairs. It also forces any identifier to its immediate left to be interpreted as a string.

    TESTVALUE to the left of '=>' is being treated as a string literal. You need to replace the '=>' with a comma.

    Also, a bareword inside braces is considered a string literal unless you tell perl to evaluate it by prepending a '+'. So $hashValue = %hash1->{TESTVALUE}; should be $hashValue = %hash1->{+TESTVALUE};

    Instead of writing %hash1->{1}, you could write $hash1{1}.

    #!/usr/local/bin/perl -w use strict; use constant TESTVALUE => 1; my %hash1 = (TESTVALUE , "OK"); my %hash2 = (123 => TESTVALUE); my $hashValue; # Try 1 $hashValue = $hash1{1}; # Try 2 $hashValue = $hash1{+TESTVALUE}; # Try 3 $hashValue = $hash1{$hash2{123}};

    Update:Fixed %hash2->{123} in last test.

    --- print map { my ($m)=1<<hex($_)&11?' ':''; $m.=substr('AHJPacehklnorstu',hex($_),1) } split //,'2fde0abe76c36c914586c';
Re: Hash values and constants
by Wonko the sane (Deacon) on Jan 12, 2003 at 15:28 UTC
    In the assignment to the hash, Perl does not know that 'TESTVALUE' is a constant, without an additional hint.

    adding a '&' or () to the constants name, will be enough of a hint to give you the desired results.

    #!/usr/local/bin/perl -w use strict; use Data::Dumper; use constant TESTVALUE1 => 1; use constant TESTVALUE2 => 2; use constant TESTVALUE3 => 3; my %hash; $hash{ TESTVALUE1 } = 'OK'; $hash{ &TESTVALUE2 } = 'OK'; $hash{ TESTVALUE3() } = 'OK'; print Dumper( \%hash );
    Outputs:
    :!./test.pl $VAR1 = { '2' => 'OK', 'TESTVALUE1' => 'OK', '3' => 'OK' };

    Data::Dumper, is great when there is a doubt about what is happening inside of a data structure assignment.

    Wonko

Re: Hash values and constants
by Aristotle (Chancellor) on Jan 12, 2003 at 16:23 UTC
    As the others have mentioned, what you're tripping over is a DWIM (Do What I Mean) feature of Perl: under certain circumstances, some words are assumed to have quotes around them when used on the left of the double arrow (or "fat comma") and in hash lookup curlies. (Did I miss any cases? There's also special rules for package names, but they're a bit different.) You can tell Perl's parser that you really didn't mean a string there by adding the correct incantation:
    #!/usr/local/bin/perl -wl use strict; use constant TESTVALUE => 1; my %hash1 = (TESTVALUE() => "OK"); my %hash2 = (123 => TESTVALUE); my $hashValue; print $hash1{1}; print $hash1{+TESTVALUE}; print $hash1{$hash2{123}};
    As you see, you do not have to use the comma instead of the double arrow - as long as Perl knows you mean the left side to be an expression, not a string. The same is true for hash lookup curlies. Note that prepending a plus sign won't work for the fat comma, though appending parens will work for the hash lookup. It's a bit confusing at first to remember which rules apply where, but you'll get used to them quick. In practice I find the specific rules and exceptions chosen to be the most convenient ones.

    Makeshifts last the longest.

      Besides -foo I can't come up with more other cases of "autoquoting". (But there always seem to be yet one more case! :))

      ihb
Re: Hash values and constants
by Marcello (Hermit) on Jan 12, 2003 at 15:51 UTC
    Thanks for all your input, it's perfectly clear (and rather obvious when you know the answer...:)