Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I dereference a hash that's been returned from a method of a class?

I have a class with a method that returns a hash. Ordinarily, I would get the result like so:

%resp = $myclass->sub($foo);

And then access members of the returned hash like this:

$resp{key}{subkey};

in the case of a 2d hash.

I figure there must be a way to combine this into a single, elegant line, something like this:

$myclass->sub($foo)->{key}{subkey}

This obviously is not dereferenced properly as Perl returns this when trying to run the code:

Can't use string ("1/8") as a HASH ref

In trying random dereferencing sequences, from looking "References quick reference" on Perlmonks, I came up with the following, which Perl does not complain about, but also does not return what I'm looking for:

$%{$myclass->sub($foo)}->{key}{subkey}

Can somebody tell me what the magic dereferencing escape sequence is to do this?

like image 221
sgsax Avatar asked Feb 12 '10 21:02

sgsax


4 Answers

What you are trying to do is neither elegant nor advisable. You have somehow managed to invoke the routine in scalar context (that's what the "1/8" corresponds to).

Return a hash reference.

Now, take a look at:

#!/usr/bin/perl

package My::Mine;

use strict; use warnings;

sub test {
    my %h = (
        a => { z => 1},
        b => { y => 2},
    );
    return %h;
}

package main;

use strict; use warnings;

my $class = 'My::Mine';

print { $class->test }->{a}{z}, "\n";

That will not work. Instead, you will have to do:

print +{ $class->test }->{a}{z}, "\n";

Now, that's elegant (Not!) See perldoc -f print.

Long story short, return a reference to the hash.

Note that the fresh anonymous hash you are constructing is not free. Nor is the cost of returning a hash as a flat list from a subroutine.

like image 148
Sinan Ünür Avatar answered Nov 15 '22 22:11

Sinan Ünür


Changing the sub to return a hash reference would work best, but to get the functionality you are looking for:

{ $myclass->sub($foo) }->{key}{subkey}

which will create a hash reference from the list returned by sub, and then immediately dereference it

Edit: The advantage to returning a hashref from your sub rather than a hash (as a list) is largely one of performance. In the hashref case, the hash is created once, and then accessed. In the list case, the hash is created, then converted into a list, then created again, and then dereferenced. For small hashes this wont take too much time, but for larger ones, it is just unnecessary work for the runtime. Basically, if you plan to use the data as a list in some places, and as a hash in others, returning the hash as a list is ok. But if you are always planning to use it as a hash, returning the reference is clearer and faster.

like image 20
Eric Strom Avatar answered Nov 15 '22 22:11

Eric Strom


I'd return a HASH reference from the sub instead. Otherwise (probably) your hash is turned into a LIST then into a HASH again for no reason:

sub mysub() {
  ...
  return \%myhash;
}

There is less copying involved when returning the reference hence more efficient.

like image 2
ziya Avatar answered Nov 15 '22 22:11

ziya


Just return a hashref instead of a hash:

$myclass->sub($foo)->{key}->{subkey}

like image 1
DVK Avatar answered Nov 15 '22 20:11

DVK