http://qs321.pair.com?node_id=984356

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

Almost through the Intermediate Perl book and came across code I do not understand and that was not explained clearly (seems to happen to me frequently in this book!). Here is the code:

sub named { #class method my $self = shift->SUPER::named(@_); my $name = $self->name; my @standings = split ' ', $STANDINGS{$name} || "0 0 0 0"; @$self{qw(wins places shows losses)} = @standings; $self; }

As background: $self is a blessed hash reference. The method 'name' returns a scalar string. %STANDINGS is a hash that is associated with a DBM file.

My question: I do not understand the line  @$self{qw(wins places shows losses)} = @standings;

I see that @standings becomes a list of 4 numbers as a result from splitting on spaces. But, in the next line, "@$self" is syntax for dereferencing an array reference, not a hash reference! Further, the use of the "{" after this indicates a hash, but I have never seen a hash defined in this way. Are they actually saying that you can have a list of keys ("qw(wins places shows losses)") and set the values by setting this to the list "@standings"?? Really?

PERL always seems to confound me with syntax! And when I cannot find the answer in perldocs etc. I just thorw up my hands and post it here!

THANK YOU for being there monks!

Replies are listed 'Best First'.
Re: hash deref confusion: Intermediate Perl
by davido (Cardinal) on Jul 30, 2012 at 06:38 UTC

    Sometimes for me I find it more readable to place the inner reference in brackets, which sort of serves to remind me that it's a reference.

    @{$self}{ qw( wins places shows losses ) } = ....

    We already know $self is a hashref. What happens when you put an @ in front of a hash, and a pair of curly brackets after it? Let's look at the similar syntax, but first remove the reference indirection (and complexity):

    @somehash{ qw( wins places shows losses ) } = ....

    That should ring a bell (you're looking at a hash slice).


    Dave

Re: hash deref confusion: Intermediate Perl
by BrowserUk (Patriarch) on Jul 30, 2012 at 06:41 UTC
    But, in the next line, "@$self" is syntax for dereferencing an array reference, not a hash reference!

    The construct you refer to is called a 'hash slice' -- see perldata#slices.

    It assignes the 4 values derived from spliting $STANDINGS{$name} (or the four 0s from the constant) to the the four keys:

    qw[ wins places shows losses ]
    .

    That one line is (mostly) equivalent to:

    $self->{wins} = $STANDINGS[ 0 ] || 0; $self->{places} = $STANDINGS[ 1 ] || 0; $self->{shows} = $STANDINGS[ 2 ] || 0; $self->{looses} = $STANDINGS[ 3 ] || 0;

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

Re: hash deref confusion: Intermediate Perl
by Anonymous Monk on Jul 30, 2012 at 06:40 UTC

    But, in the next line, "@$self" is syntax for dereferencing an array reference, not a hash reference!

    Its both; to quote myself:

    This is called a hash slice , and in a quirk of perl syntax uses the @ sigil instead of %

    my %foo; @foo{ 'hash', 'slices' } = ( 'use', 'curly braces' );

    my @bar; @bar[ 1,2,3,4 ] = ( 'array', 'slices', 'use', 'square brackets' );

    See also References quick reference

      I wouldn't really say it's a quirk. You're assigning a list of values to a list of hash slots, so the @ sigil is quite appropriate.

      perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

        I wouldn't really say it's a quirk. You're assigning a list of values to a list of hash slots, so the @ sigil is quite appropriate.

        Sure, from that perspective it makes sense, but IIRC TheLarry himself called this a mistake, its why perl6 always calls a %hash a  %hash{$key} not  $hash{$key}

      Thank you! This is a very clear and concise answer. I find it difficult to remember all the syntax in perl (also true especially of all the special symbols $....
Re: hash deref confusion: Intermediate Perl
by AnomalousMonk (Archbishop) on Jul 30, 2012 at 13:35 UTC
    Are they actually saying that you can have a list of keys ("qw(wins places shows losses)") and set the values by setting this to the list "@standings"?? Really?

    Why not just try it and see?? A toy experimental program takes less than a minute to create and run. Really!

    >perl -wMstrict -le "use Data::Dump; ;; my $self = { foo => 'bar' }; my @standings = qw(1 2 3 4); ;; @$self{ qw(wins places shows losses) } = @standings; ;; dd $self; " { foo => "bar", losses => 4, places => 2, shows => 3, wins => 1 }
      Of course, but you are taking this out of context. I would have had to know @$self{ qw... was a hash slice which was my real problem. I assumed the line worked, I did not understand the syntax.