Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: can I skip the intermediate hash variable in this case?

Tags:

hashmap

perl

At the moment, I use something like this:

my %tmpHash = routineReturningHash();
my $value = $tmpHash{'someKey'};

The only thing I need is $value, I do not need %tmpHash itself. So I am curious to know if there is a way to avoid declaring %tmpHash.

I tried

my $value = ${routineReturningHash()}{'someKey'};

but it doesn't work and outputs a strange error: "Can't use string ("1/256") as a HASH ref while "strict refs" in use".

Any ideas how it could be done?

like image 733
Georg Avatar asked Jan 04 '23 05:01

Georg


1 Answers

Create a hashref out of the returned list, which you can then dereference

my $value = { routineReturningHash() }->{somekey};

In what you tried, the ${ ... } imposes the scalar context inside. From perlref (my emphasis)

2.   Anywhere you'd put an identifier (or chain of identifiers) as part of a variable or subroutine name, you can replace the identifier with a BLOCK returning a reference of the correct type.

In the scalar context the hash is evaluated to a string with fraction involving buckets; not a hashref.


Update   I take it that there are design reasons for returning a hash as a flat list. If that isn't the case, then the clear solution is to just return a hashref from the sub.

That also saves a data copy: When you return a hash the scalars (keys and values) need be copied, to provide a list to the caller; when you return a reference only that one scalar is returned.

As for performance benefits ... if you can see a difference, you either have massive hashes which should be handled by reference anyway, or too many function calls what may need refactoring.

To return by reference you can

  • form and work with a hash in the sub and then return \%hash;

  • form a hashref directly return { key => 'value', ... };

  • If you have a big hash to work with, pass its reference and work with that

    sub work_by_ref {    
        my ($hr) = @_;
        $hr->{key} = 'value';
        return 1;
    }
    
    my %hash;
    work_by_ref(\%hash);
    say "$_ => $hash{$_}" for sort keys %hash;
    

    Be careful with this C-style approach; it is not all that usual in Perl to directly change caller's data. If you only need to fill a hash in the sub then build it there and return \%hash;

like image 195
zdim Avatar answered Jan 14 '23 00:01

zdim