Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subroutine that returns hash - breaks it into separate variables

I have a subroutine that returns a hash. Last lines of the subroutine:

print Dumper(\%fileDetails);
return %fileDetails;

in this case the dumper prints:

$VAR1 = {
          'somthing' => 0,
          'somthingelse' => 7.68016712043654,
          'else' => 'burst'
}

But when I try to dump it calling the subroutine with this line:

print Dumper(\fileDetailsSub($files[$i]));

the dumper prints:

$VAR1 = \'somthing';
$VAR2 = \0;
$VAR3 = \'somthingelse';
$VAR4 = \7.68016712043654;
$VAR5 = \'else';
$VAR6 = \'burst';

Once the hash is broken, I can't use it anymore. Why does it happen? And how can I preserve the proper structure on subroutine return?

Thanks, Mark.

like image 571
Mark Avatar asked May 28 '13 15:05

Mark


People also ask

What is Perl subroutine?

A Perl function or subroutine is a group of statements that together perform a specific task. In every programming language user want to reuse the code. So the user puts the section of code in function or subroutine so that there will be no need to write code again and again.

Can you return multiple values in Perl?

It is really easy to return multiple values from a subroutine in Perl. One just needs to pass the values to the return statement.

How do I return in Perl?

To return a value from a subroutine, block, or do function in Perl, we use the return() function. The Value may be a scalar, a list, or a hash value. Its context is selected at runtime.


2 Answers

There's no such thing as returning a hash in Perl.

Subroutines take lists as their arguments and they can return lists as their result. Note that a list is a very different creature from an array.

When you write

return %fileDetails;

This is equivalent to:

return ( 'something', 0, 'somethingelse', 7.68016712043654, 'else', 'burst' );

When you invoke the subroutine and get that list back, one thing you can do is assign it to a new hash:

my %result = fileDetailsSub();

That works because a hash can be initialized with a list of key-value pairs. (Remember that (foo => 42, bar => 43 ) is the same thing as ('foo', 42, 'bar', 43).

Now, when you use the backslash reference operator on a hash, as in \%fileDetails, you get a hash reference which is a scalar the points to a hash.

Similarly, if you write \@array, you get an array reference.

But when you use the reference operator on a list, you don't get a reference to a list (since lists are not variables (they are ephemeral), they can't be referenced.) Instead, the reference operator distributes over list items, so

\( 'foo', 'bar', 'baz' );

makes a new list:

( \'foo', \'bar', \'baz' );

(In this case we get a list full of scalar references.) And this is what you're seeing when you try to Dumper the results of your subroutine: a reference operator distributed over the list of items returned from your sub.

So, one solution is to assign the result list to an actual hash variable before using Dumper. Another is to return a hash reference (what you're Dumpering anyway) from the sub:

return \%fileDetails;

...

my $details_ref = fileDetailsSub();
print Dumper( $details_ref );

# access it like this:
my $elem = $details_ref->{something};
my %copy = %{ $details_ref };

For more fun, see:

  • perldoc perlreftut - the Perl reference tutorial, and
  • perldoc perlref - the Perl reference reference.
like image 196
friedo Avatar answered Nov 15 '22 07:11

friedo


Why not return a reference to the hash instead?

return \%fileDetails;

As long as it is a lexical variable, it will not complicate things with other uses of the subroutine. I.e.:

sub fileDetails {
    my %fileDetails;
    ... # assign stuff
    return \%fileDetails;
}

When the execution leaves the subroutine, the variable goes out of scope, but the data contained in memory remains.

The reason the Dumper output looks like that is that you are feeding it a referenced list. Subroutines cannot return arrays or hashes, they can only return lists of scalars. What you are doing is something like this:

print Dumper \(qw(something 0 somethingelse 7.123 else burst));
like image 44
TLP Avatar answered Nov 15 '22 08:11

TLP