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

Dear Monks,
my %hash = ( 'hi' => ('hello' => 'all'), 'bye' => ('later' => 'gone') ); print $hash{'all'};
How the above code prints "bye"?

Replies are listed 'Best First'.
Re: Doubt on hash keys
by tilly (Archbishop) on Jan 16, 2009 at 04:55 UTC
    Because the parens just create a flat list. What you wrote is the same as:
    my %hash = ( 'hi' => 'hello', 'all' => 'bye', 'later' => 'gone', ); print $hash{'all'};
    If you want nested hash references you need to use {}. Like this:
    my %hash = ( 'hi' => {'hello' => 'all'}, 'bye' => {'later' => 'gone'}, );
    For more on nested data structures read references quick reference.
Re: Doubt on hash keys
by ysth (Canon) on Jan 16, 2009 at 04:55 UTC
    Because parentheses almost always only affect precedence - they don't create a list (or in this case, some kind of "sub list"), and => is just a kind of comma with some semi-magical auto-quoting properties. You are initializing the hash to ( 'hi', 'hello', 'all', 'bye', 'later', 'gone' ), where 'hello', 'bye', and 'gone' are the values for the keys (respectively) 'hi', 'all', and 'later'.

    It looks like you want to make the values for $hash{'hi'} and $hash{'bye'} be hashes. Since hash values can only be scalars, you need to explicitly make a hash reference:

    my %hash = ( 'hi' => { 'hello' => 'all' }, 'bye' => { 'later' => 'gone' }, ); print $hash{'hi'}{'hello'}; # prints "all"
Re: Doubt on hash keys
by kyle (Abbot) on Jan 16, 2009 at 04:58 UTC

    What did you expect it to print?

    use Data::Dumper; my %hash = ( 'hi' => ('hello' => 'all'), 'bye' => ('later' => 'gone') ); print Dumper \%hash; __END__ $VAR1 = { 'hi' => 'hello', 'later' => 'gone', 'all' => 'bye' };

    The "sublists" that you think you have get flattened into one list qw( hi hello all bye later gone ).

    Perhaps you want:

    my %hash = ( 'hi' => {'hello' => 'all'}, 'bye' => {'later' => 'gone'} );

    See perlreftut and perlref.

Re: Doubt on hash keys
by jethro (Monsignor) on Jan 16, 2009 at 05:03 UTC

    UPDATE: I took the "How" at face value instead of interpreting it as a 'Why'. Please disregard this answer.

    The simple answer would be: print "bye";. The more serious answer: How do you want to identify the "bye"?. Do you want to get the key for which the value is a pointer to a hash with the key 'later'?

    my $result; foreach my $v (keys %hash) { if (exists $hash{$v}{'later'}) { $result= $v; }

    Or do you want the second value in the hash? That is not possible. There is no order in a hash, so there is no *second* value

    Or do you want to print all hash keys? But that would also print 'hi':

    print join(' ',keys %hash);

    Or do you really just want to print the fixed string "bye" no matter what? See my first answer.

Re: Doubt on hash keys
by targetsmart (Curate) on Jan 16, 2009 at 10:47 UTC
    What you wrote is same as
    my %hash = qw(hi hello all bye later gone);
    from man perlop
    The "=>" operator is a synonym for the comma, but forces any word (consisting entirely of word characters) to its left to be interpreted as a string (as of 5.001). This includes words that might otherwise be considered a constant or function call.