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?
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With