Re: shift in list context buggy? (scalar)
by tye (Sage) on Nov 09, 2013 at 14:32 UTC
|
my( $a, $b ) = ( shift @as, shift @bs );
There are lots of constructs where returning an empty list can be surprising if one expects a scalar to be returned.
splice returns a list and so should certainly return an empty list for edge/failure cases. Going back in time, I could see defining shift as returning either 1 scalar or returning the empty list, making that expectation clear, and that decision being a fine one. But I also can see sanity in defining shift as returning a scalar (the current reality).
Consider the relative difficulty of fixing your problem case vs. my counter-factual problem case:
while( ($x) = shift @a ) { # Broken
while( $x = shift @a ) { # Fixed
while( @a ) {
$x = shift @a; # Better
my( $a, $b ) = ( shift @as, shift @bs );
my( $a, $b ) = ( scalar shift @as, scalar shift @bs );
Also, consider how likely one is to notice the breakage between the two scenarios.
This leads me to currently slightly prefer the definition of shift as "returns a scalar", that is, the status quo.
| [reply] [d/l] [select] |
|
Thx!²
But
> Consider the relative difficulty of fixing your problem case vs. my counter-factual problem case:
while( $x = shift @a ) { # Fixed
this is not a fix because while stops, if any element of @a is false.
DB<187> @a=(1,undef,2,3,0,4,5)
DB<188> print $x while $x =shift @a
1
DB<189> print $x while $x =shift @a
23
DB<190> print $x while $x =shift @a
45
DB<191> print $x while $x =shift @a
Thats the old semipredicate problem, which can only be solved with list-assignments.¹
But I agree with you that it's most probably too late to fix that design decision...
Cheers Rolf
( addicted to the Perl Programming Language)
¹) for completeness: no defined doesn't help here, if undef is a legal value.
updates
- corrected "semipredicate problem"
- improved code example
- your "better" update is indeed better
²) best answer so far | [reply] [d/l] [select] |
|
| [reply] |
Re: shift in list context buggy?
by BrowserUk (Patriarch) on Nov 09, 2013 at 16:29 UTC
|
The problem here is that you are trying to use the return value of shift to determine if the array is empty. And since you appear to want undef to be "a legal value", there is no value that shift could return to indicate that the array is now empty.
The problem is avoided - or rather you avoid creating a problem -- by making the loop condition test the actual condition -- whether the array is empty -- and not conflating it with an operation that is unrelated to that condition:
while( @array ) {
my $x = shift @array;
# use $x.
}
This isn't a "Perl design decision" to be regretted; it's a programmer error to be avoided.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |
|
> This isn't a "Perl design decision" to be regretted; it's a programmer error to be avoided.
nope it's inconsistent, and any breach of orthogonality is a pain in the *ss and should at least be better documented.
> And since you appear to want undef to be "a legal value", there is no value that shift could return to indicate that the array is now empty.
So according to you, the demonstrated code using splice is a programmers error!
Of course shift should return an empty array which is false.
And of course ($x)=() would result in $x=undef without being true. This would be consistent with Perl's usual behavior.
DB<196> $x=42
=> 42
DB<197> ( ($x) = () ) ? "$x" : "false"
=> "false"
DB<198> $x
=> undef
Please read the code examples already given before replying.
Cheers Rolf
( addicted to the Perl Programming Language)
update
expanded code | [reply] [d/l] [select] |
|
So according to you, the demonstrated code using splice is a programmers error!
WTF did you dream that incomprehensible conclusion up from?
It is neither stated nor implied, nor logically derivable from anything I posted.
You just made it up in an attempt to misdirect.
Of course shift should return an empty array which is false.
Why "of course"?
splice can return multiple values, so when it has nothing to return, it makes sense to return an empty list.
Conversely, shift can only ever return a single value; so why would it ever return a list. Even an empty one.
Of course, it could return an empty list, and that would allow your construct to 'work'.
But it doesn't and never has! And -- other than to make your peculiar construct work -- there is no reason why it should.
Thus, it is your construct that is at fault.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
Re: shift in list context buggy?
by hdb (Monsignor) on Nov 09, 2013 at 13:51 UTC
|
use strict;
use warnings;
use Data::Dumper;
my @a = ( 1, 2 );
my $x;
my @b;
while( @b = ( $x ) = shift @a ) {
print Dumper \@b;
}
| [reply] [d/l] [select] |
|
DB<178> $x=()
=> undef
It's list context, no reason to act differently to splice.
Cheers Rolf
( addicted to the Perl Programming Language)
¹) tl;dr ? | [reply] [d/l] |
|
"shift could easily return an empty list and $x is still undef."
It could easily, yes. But it doesn't. And it's documented as retuning undef. To do something different may well subtly break a lot of code on CPAN.
That said, shift is one of those keywords that Perl allows you to override...
use subs 'shift';
sub shift (+) {
my $arr = $_[0];
@$arr ? CORE::shift(@$arr) : ();
}
use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
| [reply] [d/l] [select] |
|
|
|
|
|
| [reply] |
Re: shift in list context buggy?
by Beechbone (Friar) on Nov 12, 2013 at 13:33 UTC
|
To me it's perfectly clear why those two behave differently: shift() returns a scalar, splice() returns a list.
Putting a function that is "scalar context only" in a list context will give you a list with one element. No special magic to (surprisingly) return an empty list here.
Many builtins have list context semantics, but for shift() I'd have no idea what would make sense. Although a "shift ARRAY, COUNT" semantics might be handy sometimes. But even then I'd expect shift to always return exactly COUNT elements, even if ARRAY was empty.
| [reply] |
|
| [reply] |
|
| [reply] |
|
|
|
|
|
Re: shift in list context buggy?
by karlgoethebier (Abbot) on Nov 10, 2013 at 13:06 UTC
|
"This will never stop..."
So just don't do it ;-)
Sorry bro, i can't follow you. With due respect, isn't that nitpicking?
My best regards, Karl
«The Crux of the Biscuit is the Apostrophe»
| [reply] |