Alsciende
Alsciende

Reputation: 26971

Are references better return values in Perl functions?

What are the pros and cons of returning an array or a hash compared to returning a reference on it?

Is there an impact on memory or execution time?

What are the functional differences between the two?

sub i_return_an_array
{
    my @a = ();
    # push things in @a;
    return @a;
}

sub i_return_a_ref
{
    my @a = ();
    # push things in @a;
    return \@a;
}

my @v = i_return_an_array();
my $v = i_return_a_ref();

Upvotes: 11

Views: 5154

Answers (5)

ikegami
ikegami

Reputation: 386331

Note that it's not actually possible to return an array or a hash from a function. The only thing that a function can return is a list of scalars. When you say return @a, you are returning the contents of the array.

In certain programs, it works out more cleanly to return the contents of the array. In certain programs, it works out more cleanly to return a reference to the array. Make your decision case by case.

Upvotes: 1

manu_v
manu_v

Reputation: 1258

Short answer: it depends on the size of what you return. If it's small, you can return the whole array.

For details, see Stack Overflow question Is returning a whole array from a Perl subroutine inefficient?.

Upvotes: 2

Schwern
Schwern

Reputation: 165198

As far as interface is concerned, returning an array allows you to process it easier with things like map and grep without having to resort to @{bletchorousness}.

But with hashes, its often more useful to return a reference because then you can do clever things like my $val = function->{key} without having to assign to an intermediate variable.

Upvotes: 5

Dave Sherohman
Dave Sherohman

Reputation: 46207

Yes, there is an impact on memory and execution time - returning a reference returns a single (relatively small) scalar and nothing else. Returning an array or hash as a list makes a shallow copy of the array/hash and returns that, which can take up substantial time to make the copy and memory to store the copy if the array/hash is large.

The functional difference between the two is simply a question of whether you work with the result as an array/hash or as an arrayref/hashref. Some people consider references much more cumbersome to work with; personally, I don't consider it a significant difference.

Another functional difference is that you can't return multiple arrays or hashes as lists (they get flattened into a single list), but you can return multiple references. When this comes up, it's a killer detail that forces you to use references, but my experience is that it only comes up very rarely, so I don't know how important I'd consider it to be overall.

Going to the title question, I believe that the most important factor regarding returning lists vs. references is that you should be consistent so that you don't have to waste your time remembering which functions return arrays/hashes and which return references. Given that references are better in some situations and, at least for me, references are never significantly worse, I choose to standardize on always returning arrays/hashes as references rather than as lists.

(You could also choose to standardize on using wantarray in your subs so that they'll return lists in list context and references in scalar context, but I tend to consider that to be a largely pointless over-complication.)

Upvotes: 9

Steve Schnepp
Steve Schnepp

Reputation: 4700

The performance impact is more noticeable when the array is getting bigger, but only around 50% on perl 5.10.

I usually prefer to return a reference, since it makes the code easier to read : a function has only one return value, and avoids some pitfalls (automatic scalar evaluation) as the post referenced by manu_v mentioned.

#! /usr/bin/perl
use Benchmark;

sub i_return_an_array
{
    my @a = (1 .. shift);
    # push things in @a;
    return @a;
}

sub i_return_a_ref
{
    my @a = (1 .. shift);
    # push things in @a;
    return \@a;
}

for my $nb (1, 10, 100, 1000, 10000) {
        Benchmark::cmpthese(0, {
                "array_$nb" => sub { my @v = i_return_an_array($nb); },
                "ref_$nb" => sub { my $v = i_return_a_ref($nb); },
        });
}

returns :

            Rate   ref_1 array_1
ref_1   702345/s      --     -3%
array_1 722083/s      3%      --
             Rate array_10   ref_10
array_10 230397/s       --     -29%
ref_10   324620/s      41%       --
             Rate array_100   ref_100
array_100 27574/s        --      -47%
ref_100   52130/s       89%        --
             Rate array_1000   ref_1000
array_1000 2891/s         --       -51%
ref_1000   5855/s       103%         --
             Rate array_10000   ref_10000
array_10000 299/s          --        -48%
ref_10000   578/s         93%          --

On other versions of perl, figures might be different.

Upvotes: 9

Related Questions