stat() bug

S

ssojoodi

Hello,

While debugging a Perl script, I came across a statement like this:

my @myarray = ("str1", "str2", "str3", "str4");
my $foo = (stat(@myarray))[2];
print $foo;

[result]: str3

I know that this is not the proper usage of the stat function, but I'm
wondering why this script works! I could not find documentation on
this within the perlfunc manual, so I figured this may be a bug.

Any ideas?

Regards,
Sahand
 
P

Paul Lalli

While debugging a Perl script, I came across a statement like this:

my @myarray = ("str1", "str2", "str3", "str4");
my $foo = (stat(@myarray))[2];
print $foo;

[result]: str3

I know that this is not the proper usage of the stat function, but I'm
wondering why this script works! I could not find documentation on
this within the perlfunc manual, so I figured this may be a bug.

Any ideas?

Running the above code through -MO=Deparse shows us:
my(@myarray) = ('str1', 'str2', 'str3', 'str4');
my $foo = (stat @myarray)[2];
print $foo;
From that, you can see that '@myarray' is not being passed as an
argument to stat, but rather that array is being expanded so that the
expression is really saying:
(stat 'str1', 'str2', 'str3', 'str4')[2]

stat is defined as a unary operator, so `stat 'str1'` binds more
tightly than does the comma operator. Therefore, the list that's
created above is the list containing: (return_val_of_stat('str1'),
'str2', 'str3', 'str4')

Since the entire operation is being done in scalar context (that is,
you are assigning to the scalar variable $foo, the stat() call is also
done in scalar context, so it simply returns a true or false value, as
defined by the relevant perldoc.

You are then taking the third element of that list, which is 'str3'.

(Please note that I am mildly confused as to why @myarray isn't forced
into scalar context by the stat call, rather than expanded into a list,
but this does explain the results that are created)

Paul Lalli
 
U

usenet

my @myarray = ("str1", "str2", "str3", "str4");
my $foo = (stat(@myarray))[2];
print $foo;
[result]: str3

I know that this is not the proper usage of the stat function, but I'm
wondering why this script works!

I'm not sure if you could call it a 'bug' because, as you say, it's not
the proper use of the function.

But it does seem it ought to throw at least a warning. Interestingly
enough:

#!/usr/bin/perl
use strict; use warnings;
my @myarray = ("str1", "str2", "str3", "str4");
print stat @myarray;
__END__

[output:]str1str2str3

(notice the array has been pop()ped).
 
A

Anno Siegel

Hello,

While debugging a Perl script, I came across a statement like this:

my @myarray = ("str1", "str2", "str3", "str4");
my $foo = (stat(@myarray))[2];
print $foo;

[result]: str3

I know that this is not the proper usage of the stat function, but I'm
wondering why this script works! I could not find documentation on
this within the perlfunc manual, so I figured this may be a bug.

Any ideas?

What's happening is rather bizarre, especially when you play around
with

my @myarray = qw( str0 str1 str2 str3 str4);
my @foo = stat( @myarray[1 .. 4]);
print "@foo\n";

However, since the documentation doesn't say what stat() does when called
with more than one argument, it is rather a case of "Don't do that, then".
I guess bailing out with an error message would be better behavior, but
I'm not filing a bug because of this.

I wouldn't trust a program that uses this construct. What were they
thinking stat() was doing?

Anno
 
P

Paul Lalli

my @myarray = ("str1", "str2", "str3", "str4");
my $foo = (stat(@myarray))[2];
print $foo;
[result]: str3

I know that this is not the proper usage of the stat function, but I'm
wondering why this script works!

I'm not sure if you could call it a 'bug' because, as you say, it's not
the proper use of the function.

But it does seem it ought to throw at least a warning. Interestingly
enough:

#!/usr/bin/perl
use strict; use warnings;
my @myarray = ("str1", "str2", "str3", "str4");
print stat @myarray;
__END__

[output:]str1str2str3

(notice the array has been pop()ped).

Not really. The array isn't being changed at all. (examine the
contents of @myarray after the print to verify). What seems to be
happening is that stat is invoking a scalar context on the list
contained in @myarray. Accordingly, the first three values are
evaluated and thrown away, and the fourth value is actually passed to
stat(). Since no such file named 'str4' actually exists on your
system, that stat call returns an empty list. The print then prints
the first through third values as is, followed by the return value of
stat('str4').

You can verify this by replacing these dummy strings with names of
actual files:

$ touch file1.txt
$ touch file2.txt
$ touch file3.txt
$ touch file4.txt
$ perl -Mstrict -w -MData::Dumper
my @files = qw/file1.txt file2.txt file3.txt file4.txt/;
my @results = stat(@files);
print Dumper(\@results);
__END__
$VAR1 = [
'file1.txt',
'file2.txt',
'file3.txt',
51987534,
591538,
33204,
1,
5111,
50,
0,
'0',
1130434354,
1130434354,
1130434354,
8192,
0
];


All very bizarre, regardless.

Paul Lalli
 
T

Tad McClellan

Paul Lalli said:
While debugging a Perl script, I came across a statement like this:

my @myarray = ("str1", "str2", "str3", "str4");
my $foo = (stat(@myarray))[2];
print $foo;

[result]: str3

I know that this is not the proper usage of the stat function, but I'm
wondering why this script works! I could not find documentation on
this within the perlfunc manual, so I figured this may be a bug.

Any ideas?

Running the above code through -MO=Deparse shows us:
my(@myarray) = ('str1', 'str2', 'str3', 'str4');
my $foo = (stat @myarray)[2];
print $foo;
From that, you can see that '@myarray' is not being passed as an
argument to stat, but rather that array is being expanded so that the
expression is really saying:
(stat 'str1', 'str2', 'str3', 'str4')[2]

stat is defined as a unary operator, so `stat 'str1'` binds more
tightly than does the comma operator. Therefore, the list that's
created above is the list containing: (return_val_of_stat('str1'),
'str2', 'str3', 'str4')

Since the entire operation is being done in scalar context (that is,
you are assigning to the scalar variable $foo, the stat() call is also
done in scalar context,


The stat call is in *list* context (it is part of a list slice).

The list slice, in turn, is what is in scalar context.

so it simply returns a true or false value, as
defined by the relevant perldoc.

You are then taking the third element of that list, which is 'str3'.

(Please note that I am mildly confused as to why @myarray isn't forced
into scalar context by the stat call,


Me too.
 
S

SNeelakantan_C

Paul, your example provides a good idea of what stat() does. The scalar
context of a list is usually either the count of the number of elements
in the list or the last item of the list.

So the stat call stat(@files) becomes:

[ 'file1.txt', 'file2.txt', 'file3.txt', stat($file[4]) ]

The right thing to to do is to probably discard file1.txt, file2.txt
and file3.txt completely. Also, if file4.txt could not be found, I
would imagine $! or $@ to be set, instead of returning an empty list.

-SN
 
T

Tassilo v. Parseval

Also sprach Tad McClellan:

This looks like a bug to me. CORE::stat has a prototype of '*' which -
when given an array - should yield the array length. This is at least
what happens with user functions having that prototype.

Tassilo
 
J

Joe Smith

stat($file[4])
Also, if file4.txt could not be found, I
would imagine $! or $@ to be set, instead of returning an empty list.

Definitely not $@ since eval() is not being used.
You should expect $! to be set _AND_ an empty list.
-Joe
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top