Slice of a hashref - why does this work?

jdavidb on 2008-07-29T13:59:18

Every time I take a slice of a hashref I have to reteach myself the syntax. I usually do that using the debugger. I often spend way too long with the task, taking wrong turns and confusing myself to no end.

Today I noticed that this works in the debugger:

DB<1> $r = {this => 'that', these => '17'}
DB<2> @f = qw(this these)
DB<3> x {%$r}{@f}
0  'this'
1  'these'

The debugger's x command outputs this construction just fine. Yet when I try to assign the results of this expression to an array, either in the debugger or in a program, I get an error:

DB<4> @i = {%$r}{@f}
syntax error at (eval 32)[/usr/local/perl/5.10.0/lib/5.10.0/perl5db.pl:638] line 2, near "}{"

The correct syntax is:

@i = @{$r}{@f};

Hopefully I won't have to figure it out from scratch again the next time. :) But why does the invalid construction above work for the debugger's x command?


array

slanning on 2008-07-29T16:16:56

Seems to be returning the the last part:

DB<13> @r = qw(this that these 17)

DB<14> x {%$r}{@r}
0  'this'
1  'that'
2  'these'
3  17

DB<15> x {@r}
0  'this'
1  'that'
2  'these'
3  17

DB<16> x @r
0  'this'
1  'that'
2  'these'
3  17

Re:array

jdavidb on 2008-07-29T17:32:53

You're right. I'm getting keys, not values. I should pay more attention to detail. :)

So what about the debugger is making it ignore the first part in braces, I wonder.

My way of rembering it...

jarich on 2008-07-29T23:43:57

This might not help, but I remember hash slices as follows. First really it's just a hash:

my $hashref = {a => 1, b => 2, c=> 3};

# it's just a hash:
%$hashref;

Second we do our lookup:

my @of_interest = qw(a c);

%$hashref{@of_interest};

Slices return lists, so we need an @ sign instead of the %:

@$hashref{@of_interest};

Which gives us:

use strict;
use warnings;

my $hashref = {a => 1, b => 2, c=> 3};
my @of_interest = qw(a c);

print "@$hashref{@of_interest}\n";

You can go the other direction too. If it were just a regular hash (no reference) you'd write:

print "@hash{@of_interest}\n";

Because there's that reference there, you need to add in that $. But this way seems to confuse people more.

Parsed as blocks

tonyc on 2008-07-30T04:28:41

The expression you're supplying to the debugger is being parsed as a block:

tony@zeus:~$ perl -MO=Deparse -e '{%$r}{@f}'
{
        %$r;
}
{
        @f;
}
-e syntax OK

eval()ling the same expression gives the result you saw in the debugger:

tony@zeus:~$ perl -e '$r = { this => "that", these => 17 }; @f = qw(this these); @foo = eval q"{%$r}{@f}"; use Data::Dumper; print Dumper \@foo'
$VAR1 = [
                    'this',
                    'these'
                ];

Re:Parsed as blocks

jdavidb on 2008-07-30T12:45:36

Ah! Thank you for the explanation!