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
Comments 2
You are surprised about that? I’d expect any seasoned Perl 5 programmer to know that neither
@a = @b || @cnor@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.
Posted 11 May 2006 at 4:45 pm ¶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.
Posted 11 May 2006 at 9:02 pm ¶Post a Comment