A colleague at work just found this little gem in File::Copy::Recursive:
my $two = join '-', ( stat $cur )[0,1] || '';
That should pick out the device and inode, join them with a hyphen and set $two
to the empty string if the stat failed. However, there’s a precedence problem:
# Intended code. my $two = join( '-', ( stat $cur )[0,1] ) || ''; # Actual code. my $two = join '-', ( ( stat $cur )[0,1] ) || '';
Spot the difference? The ||
bit applies to the result of the list slice. But what happens when you use ||
on a list slice? Let’s look at the debugger…
DB<1> x @statinfo = stat '/etc/hosts' 0 2050 1 327794 2 33188 3 1 4 0 5 0 6 0 7 332 8 1089379886 9 1134738486 10 1134738486 11 4096 12 8 DB<2> x @statinfo[0,1] 0 2050 1 327794 DB<3> x @statinfo[0,1] || '' 0 327794 DB<4> x @statinfo[0,1,2] || '' 0 33188
So it appears that putting a list slice into scalar context always returns the last element of the list. Weird. More info (including examples at perldoc/C-style Logical Or).
Hopefully, he’ll file a bug report as it was actually tripping him up…
Update: RT#19205
2 replies on “Perl List Slice Weirdness”
You are surprised about that? I’d expect any seasoned Perl 5 programmer to know that neither
@a = @b || @c
nor@a = ( 1, 2 ) || ( 3, 4 );
DWIMs – what you have is just an instance of this. That you generated the list using a slice is a red herring.Maybe you need to re-read Japhy’s famous “List” is a Four-Letter Word article? 🙂
I doubt this will be changed in Perl 5… it’s fixed in Perl 6, though.
One more point: the
|| ''
bit is dead code.join always returns a string – when you join nothing, it returns an empty string, not undef.
I did know that lists don’t work like that at all; I was just surprised by the combination of the list slice. I’m just pleased to say that it wasn’t in my code. 🙂
OTOH, I’m always glad that I can learn more about the language, so many years after starting.