in reply to returning arrays from a sub - how clever is Perl?

Is Perl clever enough? I think Perl is stupid enough to return the entire array first and then scalar it. Don't underestimate Perl and the guys who created it ;-P

Is it neccessary? This is really a question for you, not others. Is it not all depends on your reqirement?

By the way, to improve performance, you better return array ref instead of array. (I trust you that by doing scalar @array, what you want is number of elements, not array ref)

Some demo:
use strict; use warnings; { my @a = sub1(); print join(",", @a), "\n"; my $a = sub1(); print $a, "\n";; } { my @a = sub2(); print join(",", @a), "\n"; my $a = sub2(); print $a, "\n"; print join(",", @$a), "\n"; } sub sub1 { my @my_array = (1,11,111,1111); return wantarray ? @my_array : scalar @my_array; } sub sub2 { my @my_array = (2,22,222,2222); return wantarray ? @my_array : \@my_array; }

Replies are listed 'Best First'.
Re: Re: returning arrays from a sub - how clever is Perl?
by Roger (Parson) on Oct 22, 2003 at 00:15 UTC
    Yes, as pg has pointed out, the main difference would be in the performance as return @my_array; will create a copy of the array, and this isn't efficient if all you want is just the number of element in the array. The performance difference will be significant if the size of the array is large.

    Personally, I always try to return the reference to array with return \@my_array; unless the size of the array is known to be very small.

      "return @my_array; will create a copy of the array, and this isn't efficient if all you want is just the number of element in the array."

      I don't believe it's correct that a copy of @my_array is made when return @my_array is evaluated in scalar context. Perl is smart enough to know about the context from within the subroutine. Context passes through, so to speak. No copy is made, and all that happens is that @my_array happily tells return to tell the lvalue scalar that there are 23 elements (or whatever number).

      Here is Yet Another Benchmark. I believe that this gets right down to brass tacks. All that we are comparing is how fast return @array takes place in scalar context, versus return $nonarray, also in scalar context. Thus, we can see if there is extra time being taken to create a copy of @array. I think you'll find the results surprising.

      First, the code:

      use strict; use warnings; use Benchmark; my @array; push @array, "Test string" for 1..20000; my $nonarray = "Test string"; sub passarray { return @array; } sub passscalar { return $nonarray; } my $count = 500000; timethese ( $count, { "Scalar" => sub { my $test = passscalar() }, "List" => sub { my $test = passarray() } } );

      And now for the exciting results...

      Benchmark: timing 500000 iterations of List, Scalar... List: 0 wallclock secs ( 0.73 usr + 0.00 sys = 0.73 CPU) @ 6830 +60.11/s (n=500000) Scalar: 2 wallclock secs ( 1.38 usr + 0.00 sys = 1.38 CPU) @ 3617 +94.50/s (n=500000)

      Surprised to find that the return @array; subroutine was faster than the return $nonarray;? I was. I figued that they would be about equal. There couldn't possibly be a copying of the array going on; that would take way too long. That part doesn't surprise me. What surprises me is that it's quicker to say, "I have 20,000 elements" than it is to say, "I contain the string, 'Test string'". By the way, the same time differential holds true even if $nonarray contains just a one-character string.

      The explanation that I can come up with is pure speculation: When comparing the operation of an array knowing its size, compared to the operation of a scalar knowing its value, the former is a less costly operation.


      Dave


      "If I had my life to do over again, I'd be a plumber." -- Albert Einstein