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

Are there any elegant ways to dereference an array or hash besides @{} and %{}? In my opinion, the standard method gets ugly in cases like this:

@baz = @{ $foo->{ bar }->{ baz } };

I see the problem as the @ not being close enough to the variable that it is operating on. It's next to foo when it should be close to baz.

Many people work around the problem at the expense of some elegance:

$baz_ref = $foot->{ bar }->{ baz }; @baz = @$baz_ref;

Here is a fictional alternative that requires the baz array ref to be an object instead of a primitive array:

@baz = $foo->{ bar }->{ baz }->to_array();

Here is another fictional alternative that may conflict with existing valid syntax (and therefore would not be backwards compatible if implemented):

@baz = $foo->{ bar }->@{ baz };

(As a side note, is Perl 6 going to be different in this regard?)

-Dan

Replies are listed 'Best First'.
Re: Elegant way to dereference an array or hash?
by Arunbear (Prior) on Nov 16, 2004 at 19:50 UTC
    In Perl 6, that will become
    @baz = $foo{'bar'}{'baz'};
    or
    @baz = $foo<<bar>><<baz>>;
Re: Elegant way to dereference an array or hash?
by fglock (Vicar) on Nov 16, 2004 at 20:12 UTC

    You can drop one arrow:

    use strict; my @baz; my $baz = [ 1, 2, 3 ]; my $bar = { baz => $baz }; my $foo = { bar => $bar }; @baz = @{ $foo->{ bar }{ baz } }; print "@baz\n"; # 1 2 3
Re: Elegant way to dereference an array or hash?
by NetWallah (Canon) on Nov 16, 2004 at 21:24 UTC
    The methods above make COPIES of the array.

    It is possible (but not necessarily a good idea) to avoid that, using Typeglobs:

    my $foo = {bar=>{baz=> [3,4,5,6]}}; local *baz= $foo->{bar}{baz}; # typeglob ALIAS, not a copy print qq(@baz);
    The obscurity vs efficiency of this kind of code might be a worthwhile tradeoff if run frequently, and/or with large arrays, when used correctly, and documented.

        Earth first! (We'll rob the other planets later)

      I have worked on tons of legacy code that used typeglobs in this way, one thing I can suggest is a var prefix that is standardized across the codebase. It makes it a lot easier to trace things out if you are looking at $tgl_varname or some such vs $randomname when the typeglob alias is created half way across a large sub or file. Also IMHO the long form deref is better all around as it does not introduce one more var name to keep track of in my tiny head.


      -Waswas
Re: Elegant way to dereference an array or hash?
by ikegami (Patriarch) on Nov 16, 2004 at 19:52 UTC

    IIRC, Perl 6 will be @baz = $foo{bar}{baz};. In other words, it will automatically dereference when needed.

    In Perl 5, the most compact I can think of is @baz = @{$$foo{bar}{baz}};

Re: Elegant way to dereference an array or hash?
by Fletch (Bishop) on Nov 16, 2004 at 19:35 UTC

    I don't know that I'd say it's too far from what it's working on because you dereference a value, not a varaible. Whether it's in $foo or $foo->{bar}->{baz}->{quux} you're still dereferencing the same thing, a single reference. The difference in the two cases is where that value's coming from. I think the conventional wisdom is don't make your data structures deeper than they need to be, and use a temporary if it really bugs you (or if you're using something from way down the "tree" several times in the same scope).