Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.85k stars 527 forks source link

Problem with `scalar()' trying to count undefined elements #1800

Closed p5pRT closed 20 years ago

p5pRT commented 24 years ago

Migrated from rt.perl.org#3059 (status was 'resolved')

Searchable as RT3059$

p5pRT commented 24 years ago

From sridhar@sisgate.superiorinfo.com

Created by sridhar@cji.com

Following is an account of what could be a bug in perl.   $ perl -e 'print "count is "\, scalar(undef\, undef)\, "\n"'   count is Note that count is undefined here\, though it should have been 2.

OK\, assuming undef's are not counted\, then the following should not work too.   $ perl -e '@​c = (undef\, undef); print "count is "\, scalar(@​c)\, "\n"'   count is 2 But that works fine.

Is it because `scalar()' cannot count lists\, but only arrays? Doesn't sound right\, so let's check it out.   $ perl -e 'print "count is "\, scalar(1\, 2\, 3)\, "\n"'   count is 3 So scalar() can count lists\, so that's not true either.

Here are more variations of the same.   $ perl -e 'print "count is "\, scalar(1\, undef)\, "\n"'   count is Here though there is a valid value in the list\, `scalar()' breaks.

But the following does count the elements though it arrives at a wrong answer.   $ perl -e 'print "count is "\, scalar(1\, 2\, undef\, 3)\, "\n"'   count is 3

And the following doesn't count at all.   $ perl -e 'print "count is "\, scalar(1\, 2\, 3\, undef)\, "\n"'   count is

Apparently the presence of an `undef' at the end of the list seems to be causing problems.

And finally this is the version info of perl   $ perl -v

This is perl\, version 5.004

Copyright 1987-1997\, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the GNU General Public License\, which may be found in the Perl 5.0 source kit.

Perl Info ``` Site configuration information for perl 5.004: Configured by gan at Fri Aug 29 10:52:11 EDT 1997. Summary of my perl5 (5.0 patchlevel 4 subversion 0) configuration: Platform: osname=solaris, osvers=2.5.1, archname=sun4-solaris uname='sunos sisgate 5.5.1 generic_103640-08 sun4u sparc sunw,ultra-2 ' hint=recommended, useposix=true, d_sigaction=define bincompat3=y useperlio= d_sfio= Compiler: cc='cc', optimize='-O', gccversion= cppflags='' ccflags ='' stdchar='unsigned char', d_stdstdio=define, usevfork=false voidflags=15, castflags=0, d_casti32=define, d_castneg=define intsize=4, alignbytes=8, usemymalloc=y, randbits=15 Linker and Libraries: ld='cc', ldflags ='' libpth=/lib /usr/lib /usr/ccs/lib libs=-lsocket -lnsl -ldl -lm -lc -lcrypt libc=/lib/libc.so, so=so useshrplib=false, libperl=libperl.a Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=, ccdlflags=' ' cccdlflags='-Kpic', lddlflags='-G' @INC for perl 5.004: /export/home/perl5/sun4-solaris/5.004 /export/home/perl5 /export/home/perl5/site_perl/sun4-solaris /export/home/perl5/site_perl . Environment for perl 5.004: PATH=/usr/bin:/bin:/usr/lbin:/usr/sbin:/usr/ccs/bin:/raid/cvs/bin:/usr/openwin/bin:/export/home/perl5/bin:/usr/local/bin:/raid/gnu/bin:/raid/misc/bin:/opt/SUNWspro/SC4.2/bin:/export/home/sridhar/local/bin::/raid/oracle/u01/app/oracle/product/8.0.5/bin:/raid/oracle/u01/app/oracle/product/8.0.5/bin:/raid/oracle/u01/app/oracle/product/8.0.5/bin LD_LIBRARY_PATH=/export/home/sridhar/local/lib PERL_BADLANG (unset) ```
p5pRT commented 24 years ago

From @mjdominus

$ perl -e 'print "count is "\, scalar(undef\, undef)\, "\n"' count is Note that count is undefined here\, though it should have been 2.

scalar() is not a `counting' operator. It indicates that its argument should be evaluated in scalar context.

In scalar context\, the comma operator returns its right-hand argument. In this case the argument is undefined.

OK\, assuming undef's are not counted\, then the following should not work too. $ perl -e '@​c = (undef\, undef); print "count is "\, scalar(@​c)\, "\n"' count is 2

An array expression evaluated in scalar context yields the number of elements.

$ perl -e 'print "count is "\, scalar(1\, 2\, 3)\, "\n"' count is 3 So scalar() can count lists\, so that's not true either.

scalar is not counting here. It is causing the 1\,2\,3 expression to return the rightmost element\, which is 3. Try

$ perl -e 'print "count is "\, scalar(1\, 2\, 57)\, "\n"'

instead.

Summary​: This is not a bug.

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

Janardhan Sridhar wrote​:

This is a bug report for perl from sridhar@​cji.com\, generated with the help of perlbug 1.17 running under perl 5.004.

----------------------------------------------------------------- [Please enter your report here]

Following is an account of what could be a bug in perl. $ perl -e 'print "count is "\, scalar(undef\, undef)\, "\n"' count is Note that count is undefined here\, though it should have been 2.

No\, a list in a scalar context returns it last element​: undef.

OK\, assuming undef's are not counted\, then the following should not work too. $ perl -e '@​c = (undef\, undef); print "count is "\, scalar(@​c)\, "\n"' count is 2 But that works fine.

Yes\, because @​c\, in a scalar context\, returns its number of elements​: 2

Is it because `scalar()' cannot count lists\, but only arrays? Doesn't sound right\, so let's check it out.

scalar doesn't count anything\, it simply forces a scalar context.

$ perl -e 'print "count is "\, scalar(1\, 2\, 3)\, "\n"' count is 3 So scalar() can count lists\, so that's not true either.

No\, simply last element is 3.

Here are more variations of the same. $ perl -e 'print "count is "\, scalar(1\, undef)\, "\n"' count is Here though there is a valid value in the list\, `scalar()' breaks.

Last element is undef

But the following does count the elements though it arrives at a wrong answer. $ perl -e 'print "count is "\, scalar(1\, 2\, undef\, 3)\, "\n"' count is 3

Right answer​: last element is 3

And the following doesn't count at all. $ perl -e 'print "count is "\, scalar(1\, 2\, 3\, undef)\, "\n"' count is

Last element is undef (please\, no more examples !)

Apparently the presence of an `undef' at the end of the list seems to be causing problems.

No. You just make a wrong assumption both about scalar and lists in a scalar context.

François

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

Janardhan Sridhar \sridhar@​cji\.com writes​:

OK\, assuming undef's are not counted\, then the following should not work too. $ perl -e '@​c = (undef\, undef); print "count is "\, scalar(@​c)\, "\n"' count is 2 But that works fine.

Is it because `scalar()' cannot count lists\, but only arrays? Doesn't sound right\, so let's check it out. $ perl -e 'print "count is "\, scalar(1\, 2\, 3)\, "\n"' count is 3 So scalar() can count lists\, so that's not true either.

Scalar cannot count lists - it returns the last element of the list​:

nick@​bactrian​:\~ > perl -e 'print "count is "\, scalar(1\, 2\, 17)\, "\n"' count is 17

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

This does point out the annoying overloading of () in perl.

$ perl -le 'print scalar(10\,20\,30)' 30 # good\, makes sense

$ perl -le 'print scalar(qw(10 20 30))' 3 # also makes sense\, qw is obviously a list

$ perl -le 'print scalar((10\,20\,30))' 30 # Hm...

Parentheses are used for grouping (precedence)\, parameters\, and lists. The first two don't conflict with each other\, but the third conflicts with both. Anyone else find the output of

sub f ($) { scalar @​_ }; print f (8\,9);

a little unexpected? Though it's probably less confusing the way it is. It's just that in

sub w { ("a"\, "b"\, "c") } sub f ($) { shift } print f w;

you can't replace w with a list. With an array\, yes\, but not a list. Unless it's a qw list. In which case it'll work\, but spam you with

Use of implicit split to @​_ is deprecated at -e line 1.

I wonder if it would help to add yet another ugly qw-like thing for listification. Then if you ever need to be explicit about what you're doing\, you can be. I know it always takes me a few tries to get

% perl -le 'print stat("/tmp")[1]' Can't use subscript on stat at -e line 1\, near "1]" Execution of -e aborted due to compilation errors. % perl -le 'print (stat("/tmp"))[1]' Can't use subscript on print at -e line 1\, near "1]" Execution of -e aborted due to compilation errors. % perl -le 'print((stat("/tmp"))[1])' 2

to work. print ql(stat "/tmp")[1] isn't pretty\, but it'd be predictable.

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

$ perl -le 'print scalar(10\,20\,30)' 30 # good\, makes sense

$ perl -le 'print scalar(qw(10 20 30))' 3 # also makes sense\, qw is obviously a list

qw() is synactically split ' '\, q()\, and split in scalar context piddles around with @​_ and returns @​_ (in scalar context\, believe it or not).

$ perl -le 'print scalar((10\,20\,30))' 30 # Hm...

Those parens are useless. scalar() means "whatever I get I am to evaluate in scalar context"\, and sending it a list of arguments means that the comma operator gets to stretch its wings. The comma operator evals its left-hand operand\, discards the results\, and returns its right-hand operand. This makes a "list" in scalar context appear to return its last element.

sub f ($) { scalar @​_ }; print f (8\,9);

No. YOU cannot replicate the scalar() function in Perl (unless you do some crazy-ass stuff that I don't happen to know of). The prototype of $ does not mean "put this in scalar context"\, it means "this argument is a scalar". Saying​:

  sub f ($);   @​a = (8\,9);   f(@​a);   f(8\,9);

\, those last two lines are NOT the same. Please realize this.

sub w { ("a"\, "b"\, "c") } sub f ($) { shift } print f w;

f() expects a single value\, in scalar context. The return value of w() in scalar context is "c".

I wonder if it would help to add yet another ugly qw-like thing for listification. Then if you ever need to be explicit about what you're doing\, you can be. I know it always takes me a few tries to get

In Perl 5.6\, qw() returns a real list at compile-time\, but seeing your next examples\, this isn't what you're talking about.

% perl -le 'print stat("/tmp")[1]' Can't use subscript on stat at -e line 1\, near "1]" Execution of -e aborted due to compilation errors.

FUNCTION[subcript] is not valid syntax.

% perl -le 'print (stat("/tmp"))[1]' Can't use subscript on print at -e line 1\, near "1]" Execution of -e aborted due to compilation errors.

FUNCTION[subscript] is still not valid syntax. Your space after 'print' means little. It's still seen as

  print(stat("/tmp")) [1]; # space added for clarity

which is subscripting a function.

% perl -le 'print((stat("/tmp"))[1])' 2

(LIST)[subscript] is very allowed. Consider too​:

  print +(stat("/tmp"))[1];

Unary + is a funny little bugger that allows you to save 5 characters here​:

  sub make_hash1 {   { @​_ } # oh\, just another little block\, not a hashref   }

  sub make_hash2 {   return { @​_ } # explicit hash ref   }

  sub make_hash3 {   + { @​_ } # unary + un-block-ifies that   }

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

On Apr 10\, Jeff Pinyan said​:

qw() is synactically split ' '\, q()\, and split in scalar context piddles around with @​_ and returns @​_ (in scalar context\, believe it or not).

That was before 5.6\, of course. qw() behaves similarly\, but creates a list at compile time -- read perldelta to find out how this changes your life in many exciting ways.

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

In message \Pine\.GSO\.4\.21\.0004101735130\.16448\-100000@​crusoe\.crusoe\.net   Jeff Pinyan \jeffp@​crusoe\.net wrote​:

On Apr 10\, Jeff Pinyan said​:

qw() is synactically split ' '\, q()\, and split in scalar context piddles around with @​_ and returns @​_ (in scalar context\, believe it or not).

That was before 5.6\, of course. qw() behaves similarly\, but creates a list at compile time -- read perldelta to find out how this changes your life in many exciting ways.

Indeed. Hence in 5.6 you get 30 and not 3 for the second example​:

gosford [~] % perl5.6.0 -le 'print scalar(qw(10 20 30))' 30

Tom

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

Jeff Pinyan wrote​:

$ perl -le 'print scalar((10\,20\,30))' 30 # Hm...

Those parens are useless. scalar() means "whatever I get I am to evaluate in scalar context"\, and sending it a list of arguments means that the comma operator gets to stretch its wings. The comma operator evals its left-hand operand\, discards the results\, and returns its right-hand operand. This makes a "list" in scalar context appear to return its last element.

Er... yes\, I know. I was complaining about it\, not wondering at it.

sub f ($) { scalar @​_ }; print f (8\,9);

No. YOU cannot replicate the scalar() function in Perl (unless you do some crazy-ass stuff that I don't happen to know of). The prototype of $ does not mean "put this in scalar context"\, it means "this argument is a scalar". Saying​:

sub f ($); @​a = (8\,9); f(@​a); f(8\,9);

\, those last two lines are NOT the same. Please realize this.

Heh? Yes\, they are not the same\, but only because () is overloaded (via toke.c) after a bareword to mean a function call. Try this​:

sub w { print wantarray ? "list" : "scalar" }; sub f1 ($) { } sub f2 { } f1 w; f2 w;

So maybe I just don't understand what you mean by there being a difference between "put this in scalar context" and "this argument is a scalar"? Looks like scalar context to me. Or are you just saying that sub myscalar ($) { shift } doesn't act the same as scalar when given a list? That's () overloading again.

But again\, I think you're not understanding that I'm just illustrating the overloading of ().

sub w { ("a"\, "b"\, "c") } sub f ($) { shift } print f w;

f() expects a single value\, in scalar context. The return value of w() in scalar context is "c".

I wonder if it would help to add yet another ugly qw-like thing for listification. Then if you ever need to be explicit about what you're doing\, you can be. I know it always takes me a few tries to get

In Perl 5.6\, qw() returns a real list at compile-time\, but seeing your next examples\, this isn't what you're talking about.

% perl -le 'print stat("/tmp")[1]' Can't use subscript on stat at -e line 1\, near "1]" Execution of -e aborted due to compilation errors.

FUNCTION[subcript] is not valid syntax.

I know. I was just leading up to the next one​:

% perl -le 'print (stat("/tmp"))[1]' Can't use subscript on print at -e line 1\, near "1]" Execution of -e aborted due to compilation errors.

FUNCTION[subscript] is still not valid syntax. Your space after 'print' means little. It's still seen as

And that's only because () is overloaded to be function invocation. My proposed version would be

% perl -le 'print ql(stat("/tmp"))[1]'

which is horribly ugly but very explicit -- foo ql(expr) is the bareword foo followed by a list\, never the function foo called with expr as its argument.

% perl -le 'print((stat("/tmp"))[1])' 2

(LIST)[subscript] is very allowed. Consider too​:

print +(stat("/tmp"))[1];

True. So in some cases you can use a different weird explicit context-forcing hack to avoid using my proposed explicit context-forcing hack. ;-) But they're really different ways to skin the same cat -- you're saying "A is a scalar\, dammit!" and I'm saying "B is a list\, dammit!" They end up the same because A is B[1].

Sorry if I was unclear about the point I was trying to make. I'm saying the character '(' is overloaded\, which can be very confusing and/or inconvenient at times.