http://qs321.pair.com?node_id=663986


in reply to Re: regexp list return 5.6 vs 5.8
in thread regexp list return 5.6 vs 5.8

A slice is not an array. What you return is what you get.

Indeed, but that distinction isn't defined for subroutine return. From perlsub:

The Perl model for function call and return values is simple: all functions are passed as parameters one single flat list of scalars, and all functions likewise return to their caller one single flat list of scalars. Any arrays or hashes in these call and return lists will collapse, losing their identities--but you may always use pass-by-reference instead to avoid this. Both call and return lists may contain as many or as few scalar elements as you'd like. (Often a function without an explicit return statement is called a subroutine, but there's really no difference from Perl's perspective.)

...

A "return" statement may be used to exit a subroutine, optionally specifying the returned value, which will be evaluated in the appropriate context (list, scalar, or void) depending on the context of the subroutine call. If you specify no return value, the subroutine returns an empty list in list context, the undefined value in scalar context, or nothing in void context. If you return one or more aggregates (arrays and hashes), these will be flattened together into one large indistinguishable list.

Subroutines return a list of scalars - that's it. Nothing is said about how flattening of aggregates is done, nor is any distinction made between arrays and plain lists.

I'd not see that as a language feature (muss less a desired one), but as a dark corner which should be inspected for sanity. All of the following snippets should behave the same way:

perl -le 'sub x {@x = qw(a b c); @x }; $r=x; print $r' 3 perl -le 'sub x {@x = qw(a b c); ()=@x }; $r=x; print $r' 3 perl -le 'sub x {@x = qw(a b c); @x[0..$#x] }; $r=x; print $r' c perl -le 'sub x {@x = qw(a b c); ()=@x[0..$#x] }; $r=x; print $r' 3

Any formal explanation why the third and fourth of these (should) yield different output?

Last but not least - allowing a more relaxed coding style in test scripts: IMHO that is the place where most robust code is required: flawed tests are useless.

--shmem

_($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                              /\_¯/(q    /
----------------------------  \__(m.====·.(_("always off the crowd"))."·
");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

Replies are listed 'Best First'.
Re^3: regexp list return 5.6 vs 5.8
by Sixtease (Friar) on Jan 24, 2008 at 11:37 UTC

    Very good points. I'll try to be more disciplined with test.

    What about this one:

    perl -le 'sub x { return qw(a b c);}; $r=x; print $r' c

    This returns the plain list and that's what I want to mimic having it in an array. Arrays and list assignments have special meanings in scalar context. Slices do not. I don't know excactly where but it is documented. (I mean, it's documented that arrays and list assignments have the special scalar-context behavior, not that slices don't :-))

    Update: From perldata:

    If you evaluate an array in scalar context, it returns the length of the array. (Note that this is not true of lists, which return the last value, like the C comma operator
    List assignment in scalar context returns the number of elements produced by the expression on the right side of the assignment:

    And, as you quoted from perlsub:

    A "return" statement may be used to exit a subroutine, optionally specifying the returned value, which will be evaluated in the appropriate context
    use strict; use warnings; print "Just Another Perl Hacker\n";
      It is stated in perldata - in parens!
      Assignment is a little bit special in that it uses its left argument to determine the context for the right argument. Assignment to a scalar evaluates the right-hand side in scalar context, while assignment to an array or hash evaluates the righthand side in list context. Assignment to a list (or slice, which is just a list anyway) also evaluates the righthand side in list context.

      Then there's perlop which states that qw generates a real list at compile time, and returns the last element of that in scalar context (which AFAIK is resolved at runtime). Array slices seem to work the same way (compile time list construction).

      But that either

      • shouldn't be the case with subroutine returns, according to the docs, or
      • should be documented in the docs, like, "Subroutines return lists, except when they don't. Aggregates are returned as flattened lists, but lists are evaluated in the caller's context".

      Subroutine return values are evaluated in the caller's context on return, they are not made into a list context on exit which is then evaluated in the caller's context. This is arguably a feature...

      Thanks for bringing that up.

      --shmem

      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

      Works for me on both ancient versions of perl;-)

Re^3: regexp list return 5.6 vs 5.8
by ikegami (Patriarch) on Jan 24, 2008 at 18:29 UTC

    Subroutines return a list of scalars, but when the sub is in scalar context, that list will always have exactly one scalar in it.

    "A 'return' statement [...] will be evaluated in the appropriate context" means the op which returns the arguments to return is executed in the same context as the sub. It's the *statement* that is evaluated in the appropriate context, not the values returned.

    When evaluated in scalar context, arrays return their length. (Case 1)
    When evaluated in scalar context, lists return their last element. (Case 3)
    When evaluated in scalar context, list assignments return the number of elements assigned. (Case 2 and 4)

Re^3: regexp list return 5.6 vs 5.8
by Sixtease (Friar) on Jan 24, 2008 at 12:36 UTC

    Something that just crossed my mind and turned out to behave like I didn't expect:

    perl -le 'sub x { my @x = qw(a b c); my @y = qw(A B C D); return (@x, +@y)} my $r = x(); print $r' 4

    Must say it made me LOL :-)

    use strict; use warnings; print "Just Another Perl Hacker\n";
      From what we've already discussed I would have expected the outcome:
      • the return list is constructed at compile time.
      • at runtime, the list (@x, @y) is evaluated in the caller's context, so it resolves to the comma operator, returning it's last argument - @y
      • then the array @y is evaluated in the caller's context, which happens to be scalar, hence 4 as a result.

      Pretty much the same as

      perl -le '@x=qw(a b c);@y=qw(a b c d); $f=(@x,@y); print $f' 4

      ;-)

      --shmem

      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re^3: regexp list return 5.6 vs 5.8
by Errto (Vicar) on Jan 24, 2008 at 15:59 UTC
    You're right about the behavior of slices, but it has nothing to do with subroutine returns. See for example:
    perl -e"my @a=qw/a b c/; print scalar @a[0..2]" c
    The issue is that an array (or hash, or list) slice in scalar context returns the last element of the slice. I feel like this should be documented in perldata but a quick read of it just now didn't reveal any such indication.