Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to return the array or hash and when only the reference?

I am confused with the following.
Sometimes I see examples such as this:

my %hash = get_data();

sub get_data {
    my %data = ();
    # do processing
    return %data;
}

And similar with arrays.

my @arrays = get_data();

sub get_data {
    my @data = ();
    # do processing
    return @data;
}

I originally thought that you can not return arrays or hashes from functions only references to them.
So I don't understand what is the difference and when should we prefer over the other?
Is it related to garbage collection or too much copy of data what we choose?

like image 486
Jim Avatar asked Dec 02 '22 18:12

Jim


1 Answers

Strictly speaking, you can't return an array or a hash from a Perl subroutine. Perl subroutines return lists. Lists are similar to arrays in that they're sequences of values, but they aren't arrays. Arrays are variables. Lists are nameless, immutable, and transient data structures used to pass and return values, initialize arrays and hashes, etc. It's a somewhat subtle point, but an important one.

When you write return @data you aren't returning the @data array; you're returning a list of the values it contains. Similarly, return %data returns a list of the key/value pairs contained in the hash. Those values can be used to initialize another array or hash, which is what's happening in your examples. The initialized array/hash contains a (shallow) copy of the one used by the subroutine.

To "return" an array or hash, you must return a reference to it. e.g. return \@data or return \%data. Doing that returns a reference to the variable itself. Modifying it will affect the original array as well because it's the same storage.

Whether a sub should return an array/hash as a list (copy) or a reference is a programming decision. For subs that always return N values with positional meaning (e.g. the localtime built-in) returning a list makes sense. For subs that return arbitrarily large lists it's usually better to return a reference instead as it's more efficient.

It's even possible for a sub to decide what to return based on how it's called by using wantarray. This let's the caller decide what they want.

sub get_data {
    my @data;
    ...
    return wantarray ? @data : \@data;
}

my $aref  = get_data(); # returns a reference
my @array = get_data(); # returns a list
like image 87
Michael Carman Avatar answered Jan 02 '23 23:01

Michael Carman