Sixtease has asked for the wisdom of the Perl Monks concerning the following question:
Hello everybody,
Please, can there be a difference between what the following snippet would return on perl5.8 and perl5.6? I'm getting test failures from cpan testers (God bless them) on perl5.6, where it seems to return 1 where $_[0] has no digits.
my @rv = $_[0] =~ /^([0-9]+)$/; return @rv[0 .. $#rv];
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: regexp list return 5.6 vs 5.8
by Sixtease (Friar) on Jan 24, 2008 at 09:42 UTC | |
Is the behavior of list slice subroutine return an intended feature A slice is not an array. What you return is what you get. I don't see any magic there. You're definitely right about not golfing production code. This is from a test script however - I allow myself a little more relaxed way of coding in those. :-) I think I understand the thing now - it's an XY case if I'm correct. That subroutine's return value has been assigned to a scalar and that has been pushed to an array. Maybe this code works differently on 5.6?
What I expect and get on 5.8.8 is:
Update: Modified the code to more closely follow the original.
use strict; use warnings; print "Just Another Perl Hacker\n";
| [reply] [d/l] [select] |
by shmem (Chancellor) on Jan 24, 2008 at 11:13 UTC | |
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.) 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:
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
| [reply] [d/l] |
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:
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";
| [reply] [d/l] |
by shmem (Chancellor) on Jan 24, 2008 at 12:10 UTC | |
by hipowls (Curate) on Jan 24, 2008 at 11:43 UTC | |
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)
| [reply] [d/l] |
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:
Must say it made me LOL :-)
use strict; use warnings; print "Just Another Perl Hacker\n";
| [reply] [d/l] |
by shmem (Chancellor) on Jan 24, 2008 at 12:48 UTC | |
by Errto (Vicar) on Jan 24, 2008 at 15:59 UTC | |
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. | [reply] [d/l] |
by hipowls (Curate) on Jan 24, 2008 at 10:34 UTC | |
On Solaris 5.6.1 I got
| [reply] [d/l] |
Re: regexp list return 5.6 vs 5.8
by hipowls (Curate) on Jan 24, 2008 at 09:02 UTC | |
Running this script on Solaris produces (5.6.1) and (5.005_03)
There were no warnings, I get them when running under 5.10.0 | [reply] [d/l] [select] |
by parv (Parson) on Jan 24, 2008 at 09:08 UTC | |
Do you really get [[] in the first print statement? If so, any idea how (output of first 2 print's is [] with perl 5.8.7 on CentOS 5)? | [reply] [d/l] [select] |
by hipowls (Curate) on Jan 24, 2008 at 09:34 UTC | |
Really, I too was surprised. Changing sub test to produced changing sub test to produces Note the warning. (And I suspect there are some monks who are now saying I told you so;-) | [reply] [d/l] [select] |
by Sixtease (Friar) on Jan 24, 2008 at 09:50 UTC | |
by hipowls (Curate) on Jan 24, 2008 at 10:21 UTC | |
| |
Re: regexp list return 5.6 vs 5.8
by Anonymous Monk on Jan 24, 2008 at 07:33 UTC | |
(you haven't been messing with $[ have you?) | [reply] [d/l] [select] |
by Anonymous Monk on Jan 24, 2008 at 08:27 UTC | |
ok, but then wouldn't it be better (in the sense of being more maintainable) to write something like return wantarray ? @rv : $rv[-1]; ? | [reply] [d/l] |
by Sixtease (Friar) on Jan 24, 2008 at 07:50 UTC | |
It's not quite the same ^^. @rv is an array and in scalar context evaluates to the number of the emelents. Slicing turns it into a list and thus gives the last element instead.
use strict; use warnings; print "Just Another Perl Hacker\n";
| [reply] |
by shmem (Chancellor) on Jan 24, 2008 at 08:31 UTC | |
Is the behavior of list slice subroutine return an intended feature, is it specced somewhere (or even documented)? Or is it just an implementation detail which might some day be considered a bug and be changed thereafter? Don't golf production code ;-) --shmem
| [reply] [d/l] |
Re: regexp list return 5.6 vs 5.8
by ikegami (Patriarch) on Jan 24, 2008 at 18:12 UTC | |
In scalar context, I get the same behaviour in 5.6.0, 5.6.1, 5.8.0 and 5.8.8
In list context, I get the same behaviour in 5.6.0, 5.6.1, 5.8.0 and 5.8.8
| [reply] [d/l] [select] |
by almut (Canon) on Jan 24, 2008 at 19:15 UTC | |
I think whether you get different behaviour depends on the exact circumstances in which the evaluation happens. I would argue that you don't see a difference, because there's nothing "on the stack" (as I hypothesized in my other reply) prior to the evaluation of the slice in scalar context. If I modify your test slightly, I do get different results depending on Perl version.
5.8.4 prints foo (and no warning), while 5.8.8 and 5.10.0 print Use of uninitialized value $s in print at -e line 1. (and no "foo"). Note 1: the sub {"foo"}->() is just a way to avoid the "Useless use of a constant in void context", which I would otherwise get when simply writing "foo", ... Note 2: Windows users will probably have to swap single and double quotes (I changed them myself in the first place, because ikegami's original version would have required additional quoting with a typical Unix shell...) | [reply] [d/l] [select] |
Re: regexp list return 5.6 vs 5.8
by Sixtease (Friar) on Jan 24, 2008 at 12:29 UTC | |
I'm still very curious about the weird [[] and {{} that hipowls was getting. Maybe it's worth a thread. It would seem that I'm unable to locate the cause of the error people seem to experience testing my package on v5.6. If any of you are interested, it's Data::FeatureFactory on cpan, maybe you can have a look (make test). I'll try to find a 5.6 installation somewhere and play with it.
use strict; use warnings; print "Just Another Perl Hacker\n";
| [reply] [d/l] [select] |
by almut (Canon) on Jan 24, 2008 at 15:06 UTC | |
I get the same behaviour with 5.8.4, BTW. It seems that when the range 0..-1 is used to select the elements of the slice ($#rv is -1 when @rv is empty), the 'final element' of the slice (incorrectly) evaluates to the previous/last element on the Perl stack (or some such). With Perl versions up to at least 5.8.4, that is — but no longer with 5.8.8 and 5.10.0 (I currently don't have access to versions 5.8.5 - 5.8.7, so I can't tell when it got fixed). (Ranges like [99..98] behave the same way as [0..-1], so what seems to matter is just that the second value in the range is smaller than the first...)
With 5.8.4 (and earlier), this prints
and with 5.8.8 or 5.10.0
As has already been pointed out elsewhere in the thread, this is mostly expected behaviour, because (from perldoc -f scalar) scalar EXPR ...except for the "[foo[foo]", of course. I don't have a real explanation (probably simply a bug)... just a couple of related observations with respect to using [0..-1] with slices. When you use a literal list instead of a named array, there's still some curious behaviour in recent releases of Perl:
prints
The '"[foo" isn't numeric...' seems to suggest that with [0..-1] the value "[foo" is being used to index the element from the list... which is confirmed by this:
which prints
Looks like this "indirect indexing" feature could be useful for obfus ;) | [reply] [d/l] [select] |
by Sixtease (Friar) on Jan 24, 2008 at 17:37 UTC | |
Oh dear God, this is crazy. :-)) Thanks an awful lot for the explanation! This also explains why my test has been failing.
use strict; use warnings; print "Just Another Perl Hacker\n";
| [reply] |
by hipowls (Curate) on Jan 24, 2008 at 13:44 UTC | |
For what's worth I can confirm that it happens with ActiveState's 5.6.1, build 638 on Linux. My tool chain is too modern to build it from source;-( | [reply] |
Re: regexp list return 5.6 vs 5.8
by Sixtease (Friar) on Jan 24, 2008 at 17:51 UTC | |
OK, one more question: How do you guys recommend that I flatten lists? I mean... say I have some values in an array, or in two arrays and I want to turn it into one flat list that will not have any array-specific or similar behavior. I can want to pass it from a subroutine, from a do statement or from a map block or eval or whatever... Update: How about map $_, @stuff, @more_stuff? Update 2: Nope. As documented: "In scalar context, returns the total number of elements so generated."
use strict; use warnings; print "Just Another Perl Hacker\n";
| [reply] [d/l] [select] |
by mrpeabody (Friar) on Jan 25, 2008 at 04:38 UTC | |
OK, one more question: How do you guys recommend that I flatten lists? I mean... say I have some values in an array, or in two arrays and I want to turn it into one flat list that will not have any array-specific or similar behavior. You flatten lists like this:
But your question doesn't make a lot of sense. You seem to be asking "How do I make an array that isn't an array", and the answer to that is "You can't". If you're trying to ask "How do I return different values from a function depending on the calling context", then look into wantarray as shmem suggests. | [reply] [d/l] [select] |
by almut (Canon) on Jan 25, 2008 at 06:03 UTC | |
I think the OP is essentially asking (Sixtease please correct me if I'm wrong) how you would make something like the following snippet print "e", and not "2"
treating the combined arrays as if they had been written like
Kind of like this
but less ugly, and without having to take special care of the subtle problem you run into with older versions of Perl when the arrays are empty, and the selecting range for the slice becomes [0..-1] (what this thread is about, essentially). Irrespective of whether you'd actually need to do something like this in real-life programming, it's still a valid question in and of itself, IMO. | [reply] [d/l] [select] |
by Errto (Vicar) on Jan 24, 2008 at 18:49 UTC | |
| [reply] [d/l] [select] |