0

Would somebody be so pleasant to explain why does the next thing happen? Here is the code:

#!/usr/bin/perl
use v5.14;
use warnings;

my @arr = (1, 2, 3);

sub func
{
    return @arr;
}

push(&func(), 4);

say @arr;

When I try to run it, the output is Not an ARRAY reference at ....

I suppose that this is because &func() evaluates not to the @arr, but to a plain list 1, 2, 3 and 1 is treated as ARRAY argument to the push. Can somebody explain why does this happen, cause in the push documentation I found nothing related to this.

Thanks in advance.

d.k
  • 4,234
  • 2
  • 26
  • 38
  • 1
    Change `return @arr` to `return \@arr` – j.w.r Sep 17 '12 at 18:23
  • @j.w.r, I know that I can do that, but why `@arr` does not work? In `push` doc it is said that it accepts `ARRAY` as it first argument, so why it does not accept it. I don't ask how to get it to work, but why this does not work. – d.k Sep 17 '12 at 18:26
  • 2
    Because `func()` does not return an array, it returns a list. The various array functions (push, pop, shift, splice) can take an array argument because they have that special functionality, but in (most) other cases, arrays collapse into a list of their elements. Which is why your push statement really looks like this: `push(1,2,3,4)`. – TLP Sep 17 '12 at 18:56

1 Answers1

4

It's impossible for a sub to return an array. You are returning the result of evaluating the array in list context, which is to say you are returning a list of its content. Obviously, that's not what you want.

push will now accept a reference to an array, so you could use

sub func {
   return \@arr;
}

push(func(), 4);

Note that push required an array literal until recently, so must use the following if you want backwards compatibility:

sub func {
   return \@arr;
}

push(@{ func() }, 4);

PS — Note that I removed the &. Why are you telling Perl to ignore the prototype of a sub that has no prototype?

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • As I understood functions always return a result of last expression, not the variable. Is it right? – d.k Sep 17 '12 at 18:30
  • @caligula, `:lvalue` subs would be the exception. They'll actually return the var when called in lvalue context. – ikegami Sep 17 '12 at 18:33
  • 2
    @caligula, ...but `push` will still expect an array ref if you don't provide an array literal (something that starts with `@`), even if you used `sub func :lvalue { @arr }`. – ikegami Sep 17 '12 at 18:45