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

Dear Monks,
It is always at the moment I think I understand how it all fits together I'll run into an other problem. Let me give a few examples of how I think array and hash refs can be initiated:
$hr->{a} = "hello" ; # or @$hr{a} = "hello" ; # doesn't work!!! $ar->[0] = "hello" ; # or @$ar[0] = "hello" ; # does WORK !!!! print "value of hr = $ar->[a]\n" ; print "value of hr = $hr->{a}\n" ; # or print "value of ar = ".@$ar[0]."\n" ; print "value of hr = ".%$hr{a}."\n" ; # doesn't work!!
How come that hash and array refs work so different or (more likely) is it me doing something terribly wrong here ??

Thanks
Luca

Replies are listed 'Best First'.
Re: A better understanding of array and hash references
by jeffa (Bishop) on Dec 01, 2005 at 17:18 UTC

    Actually, the reason why your non-working examples "do not work" is simply because that @$hr{a} is ambigious: does it mean that $hr is an array reference or does it mean that the key 'a' from the hash reference $hr contains an array reference. If the case is the latter, you really should be using syntax like so:

    @{$hr->{a}} = [qw(foo bar baz)]; @{$ar->[0]} = [0 .. 9];
    Data::Dumper and References quick reference are your friends. :)

    Update: thanks for the typo correction, ikegami.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: A better understanding of array and hash references
by Fletch (Bishop) on Dec 01, 2005 at 17:20 UTC

    Yeah, works for me as well. Perhaps your confusion is with %$hr{a} which would be trying to dereference a hashref contained in the hash %hr in the value associated with the key "a".

    use Data::Dumper qw( Dumper ); $hash_a->{a} = "hello" ; @$hash_b{a} = "hello" ; $arr_a->[0] = "hello" ; @$arr_b[0] = "hello" ; print "hash_a ", Dumper( $hash_a ), "\n"; print "hash_b ", Dumper( $hash_b ), "\n"; print "arr_a ", Dumper( $arr_a ), "\n"; print "arr_b ", Dumper( $arr_b ), "\n"; __END__ hash_a $VAR1 = { 'a' => 'hello' }; hash_b $VAR1 = { 'a' => 'hello' }; arr_a $VAR1 = [ 'hello' ]; arr_b $VAR1 = [ 'hello' ];
Re: A better understanding of array and hash references
by ikegami (Patriarch) on Dec 01, 2005 at 17:16 UTC

    Contrary to what you say, both
    @$hr{a} = "hello";  # Hash slice.  Equiv to @h[0].
    and
    @$ar[0] = "hello";  # Array slice. Equiv to @a[0].
    work for me, as they should.

    ActivePerl v5.6.1 Win2k
    ActivePerl v5.8.0 WinXP
    perl v5.8.0 FreeBSD

    It's true that %$hr{a} doesn't work, but why should it? It would be equivalent to %h{a} which is not valid Perl.

    Of course, I don't know what you're using slices with just one element. The following work just as great:
    $$hr{a} = "hello";  # Same as $hr->{a}. Equiv to $h{a}.
    and
    $$ar[0] = "hello";  # Same as $ar->[0]. Equiv to $a[0].

    Update: Added to the node.

Re: A better understanding of array and hash references
by wfsp (Abbot) on Dec 01, 2005 at 17:53 UTC

    I also highly recommend using Data::Dumper as mentioned above.

    What I find helpful is to use the longhand:

    push @{$hr->{a}}, 'hello'; print "${$hr->{a}}[0]\n";

    I find that this give my eye a better chance to see that some derefencing is going on (I'm old!).

    Hang on in there! :-)

Re: A better understanding of array and hash references
by jeanluca (Deacon) on Dec 01, 2005 at 18:23 UTC
    Wow,
    and I thought I saw the light some time ago, but I realize now my dear monks, that it should have been something else.

    I get the feeling its time for me to study slices, I always thought they were not so important, but to get the whole picture I guess it is important!

    Thanks a lot
    Luca
Re: A better understanding of array and hash references
by Errto (Vicar) on Dec 04, 2005 at 03:53 UTC

    One thing that hasn't been mentioned yet in this thread is that in your example, you are only looking at one value at a time: either the hash key 'a' or the array index 0. If this is true in your real code as well, then you don't need to be using slices. In fact I would say you should not use slices for a couple of reasons:

    • Someone who has to maintain the code later will be confused as to why you're using them when unneeded
    • There's a slight performance penalty (I think)
    • When you assign to a slice instead of a single element, the right side is in list context, which can matter

    To see what I mean by that last one, try this code:

    my $hashref = {}; # initializer not needed, but helps clarity $hashref->{a} = localtime; # can also be written $$hashref{a} print "$hashref->{a}\n"; @$hashref{a} = localtime; # this is a slice because of the @ print "$hashref->{a}\n";

    The second assignment evaluates localtime in list context, but because the slice on the left side only has one element, only the first value in the returned list gets stored there, which happens to be the number of seconds.

    My preference is to be as explicit as possible so I write $hashref->{a} for single elements and @{$hashref}{'a','b'} for slices.

Re: A better understanding of array and hash references
by jeanluca (Deacon) on Dec 01, 2005 at 17:25 UTC
    sorry typo,

    @$hr{a}  = ....
    should be
    %$hr{a} = ....

      No, you have it backwards. The hash equivalent of
      @$ar[0] (or @$ar[0, 1, 2])
      is
      @$hr{a} (or @$hr{'a', 'b', 'c'})

      %$hr{a} is nonsense. Read about slices in perldata

      By the way, you shouldn't use slices for single elements.
      @$ar[0] and @$hr{a}
      should be
      $$ar[0] and $$hr{a}

      Remember: When using an index on a hash or an array, the sigil is of the type returned/assigned. Slices return/accept a list, so @ is used. When refering to a single element, $ is used. % is never used when an index is specified.

      Update: Here's a table which should help:
      Direct Using References
      Syntax 1* Syntax 2
      array element $a[0] ${$ar}[0] $ar->[0]
      slice @a[0,1,2] @{$ar}[0,1,2]
      unindexed @a @{$ar}
      hash element $h{'a'} ${$hr}{'a'} $hr->{'a'}
      slice @h{'a','b','c'} @{$hr}{'a','b','c'}
      unindexed %h %{$hr}

      * – The curly brackets around $ar and $hr are optional.

        Very nice table/overview!!!