Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split to list assignment in scalar context #11740

Open
p5pRT opened this issue Nov 8, 2011 · 9 comments
Open

Split to list assignment in scalar context #11740

p5pRT opened this issue Nov 8, 2011 · 9 comments

Comments

@p5pRT
Copy link

p5pRT commented Nov 8, 2011

Migrated from rt.perl.org#103212 (status was 'open')

Searchable as RT103212$

@p5pRT
Copy link
Author

p5pRT commented Nov 8, 2011

From ambrus@math.bme.hu

Created by ambrus@math.bme.hu

This command gives an unexpected result​:

$ perl -wE 'say scalar(($_x, $_y) = split "/", "one/two/three/four/five");'
3

One would naively think it should return 5, just like this command​:

$ perl -wE 'say scalar((@​_x) = split "/", "one/two/three/four/five");'
5

for the split returns a list of five strings and the list assignment returns
the number of scalars assigned.

The surprising behaviour of the first command is actually sort-of documented
in the perlfunc entry for split​:

  When assigning to a list, if LIMIT is omitted, or zero, Perl supplies a
  LIMIT one larger than the number of variables in the list, to avoid
  unnecessary work.

So in the first command, split("/", $s) is silently changed to split("/",
$s, 3) by the optimizer because it's assigned to a list of scalars, which
made split return three strings only. However, this documentation says this
is done only "to avoid unnecessary work", which I take as meaning this
shouldn't have an observable side effect.

I propose that you change split to use this implicit limit only when this
has no observable side effects, for example if the optimizer knows the list
assignment is always evaluated in void context.

This came up in the real world by the way, and I was utterly baffled by it
for a while​: "http​://www.perlmonks.com/?node_id=934401".

By the way, the bug still happens if you add an explicit limit of 0, eg.

$ perl -wE 'say scalar(($_x, $_y) = split "/", "one/two/three/four/five",
0);'
3

which is completely against what the docs say, as noted by core bug #3247
("https://rt-archive.perl.org/perl5/Ticket/Display.html?id=3247"; that bug says it's
resolved, but it seems it's not).

Also, the bug is still present in perlblead as of a few weeks ago.

--
Ambrus

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl 5.14.2:

Configured by ambrus at Sat Oct  1 19:00:08 CEST 2011.

Summary of my perl5 (revision 5 version 14 subversion 2) configuration:

  Platform:
    osname=linux, osvers=2.6.37, archname=x86_64-linux
    uname='linux king 2.6.37 #6 smp sun mar 13 20:15:05 cet 2011
x86_64 gnulinux '
    config_args='-Dprefix=/usr/local/perl5.14
-Dman1dir=/usr/local/share/man/man1
-Dman3dir=/usr/local/share/man/man3
-Dsiteman1dir=/usr/local/share/man/man1
-Dsiteman3dir=/usr/local/share/man/man3 -d'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=undef, usemultiplicity=undef
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-fno-strict-aliasing -pipe -fstack-protector
-I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2',
    cppflags='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
    ccversion='', gccversion='4.6.1', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t',
lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -fstack-protector -L/usr/local/lib'
    libpth=/usr/local/lib /lib/../lib64 /usr/lib/../lib64 /lib
/usr/lib /lib64 /usr/lib64 /usr/local/lib64
    libs=-lnsl -ldl -lm -lcrypt -lutil -lc
    perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc
    libc=/lib/libc-2.11.2.so, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version='2.11.2'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib
-fstack-protector'

Locally applied patches:



@INC for perl 5.14.2:
    /usr/local/perl5.14/lib/site_perl/5.14.2/x86_64-linux
    /usr/local/perl5.14/lib/site_perl/5.14.2
    /usr/local/perl5.14/lib/5.14.2/x86_64-linux
    /usr/local/perl5.14/lib/5.14.2
    /usr/local/perl5.14/lib/site_perl/5.14.1/x86_64-linux
    /usr/local/perl5.14/lib/site_perl/5.14.1
    /usr/local/perl5.14/lib/site_perl/5.14.0/x86_64-linux
    /usr/local/perl5.14/lib/site_perl/5.14.0
    /usr/local/perl5.14/lib/site_perl
    .


Environment for perl 5.14.2:
    HOME=/home/ambrus
    LANG (unset)
    LANGUAGE (unset)
    LC_CTYPE=hu_HU
    LD_LIBRARY_PATH=/home/ambrus/local/lib/
    LOGDIR (unset)
    PATH=/home/ambrus/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games
    PERL_BADLANG (unset)
    SHELL=/usr/local/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Dec 6, 2011

From @jkeenan

On Tue Nov 08 14​:37​:05 2011, b_jonas wrote​:

This is a bug report for perl from ambrus@​math.bme.hu,
generated with the help of perlbug 1.39 running under perl 5.14.2.

-----------------------------------------------------------------
[Please describe your issue here]

This command gives an unexpected result​:

$ perl -wE 'say scalar(($_x, $_y) = split "/",
"one/two/three/four/five");'
3

One would naively think it should return 5, just like this command​:

$ perl -wE 'say scalar((@​_x) = split "/", "one/two/three/four/five");'
5

But we also need to take into account the documentation for the 'scalar'
function (perldoc -f scalar)​:

#####
Because "scalar" is a unary operator, if you accidentally use a
parenthesized list for the EXPR, this behaves as a scalar comma
expression, evaluating all but the last element in void context
and returning the final element evaluated in scalar context.
This is seldom what you want.
#####

My hunch is that in your first case above, the "final element evaluated
in scalar context" would be '3', the number of elements in ( qw| three
four five | ).

Thank you very much.
Jim Keenan

@p5pRT
Copy link
Author

p5pRT commented Dec 6, 2011

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Dec 6, 2011

From @cpansprout

On Mon Dec 05 18​:08​:31 2011, jkeenan wrote​:

On Tue Nov 08 14​:37​:05 2011, b_jonas wrote​:

This is a bug report for perl from ambrus@​math.bme.hu,
generated with the help of perlbug 1.39 running under perl 5.14.2.

-----------------------------------------------------------------
[Please describe your issue here]

This command gives an unexpected result​:

$ perl -wE 'say scalar(($_x, $_y) = split "/",
"one/two/three/four/five");'
3

One would naively think it should return 5, just like this command​:

$ perl -wE 'say scalar((@​_x) = split "/", "one/two/three/four/five");'
5

But we also need to take into account the documentation for the 'scalar'
function (perldoc -f scalar)​:

#####
Because "scalar" is a unary operator, if you accidentally use a
parenthesized list for the EXPR, this behaves as a scalar comma
expression, evaluating all but the last element in void context
and returning the final element evaluated in scalar context.
This is seldom what you want.
#####

My hunch is that in your first case above, the "final element evaluated
in scalar context" would be '3', the number of elements in ( qw| three
four five | ).

But list assignment in scalar context returns the number of elements on
the rhs.

That’s separate from the comma operator in scalar context.

Thank you very much.
Jim Keenan

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Dec 6, 2011

From @tamias

On Mon, Dec 05, 2011 at 06​:08​:32PM -0800, James E Keenan via RT wrote​:

On Tue Nov 08 14​:37​:05 2011, b_jonas wrote​:

This command gives an unexpected result​:

$ perl -wE 'say scalar(($_x, $_y) = split "/",
"one/two/three/four/five");'
3

One would naively think it should return 5, just like this command​:

$ perl -wE 'say scalar((@​_x) = split "/", "one/two/three/four/five");'
5

But we also need to take into account the documentation for the 'scalar'
function (perldoc -f scalar)​:

#####
Because "scalar" is a unary operator, if you accidentally use a
parenthesized list for the EXPR, this behaves as a scalar comma
expression, evaluating all but the last element in void context
and returning the final element evaluated in scalar context.
This is seldom what you want.
#####

That paragraph is not relevant here. The argument to scalar in the first
example is not a parenthesized list; it is a list assignment. A list
assignment in scalar context returns the number of elements on its
right-hand side.

My hunch is that in your first case above, the "final element evaluated
in scalar context" would be '3', the number of elements in ( qw| three
four five | ).

No, it's 3, the number of elements in ( qw| one two three/four/five | ).

perldoc -f split

  The LIMIT parameter can be used to split a line partially

  ($login, $passwd, $remainder) = split(/​:/, $_, 3);

  When assigning to a list, if LIMIT is omitted, or zero, Perl
  supplies a LIMIT one larger than the number of variables in
  the list, to avoid unnecessary work. For the list above LIMIT
  would have been 4 by default.

To get 5 instead, specify a limit of -1​:

$ perl -wE 'say scalar(($_x, $_y) = split "/", "one/two/three/four/five", -1);'
5

This is not a bug.

Ronald

@p5pRT
Copy link
Author

p5pRT commented Dec 6, 2011

From @cpansprout

On Mon Dec 05 18​:33​:01 2011, rjk@​tamias.net wrote​:

On Mon, Dec 05, 2011 at 06​:08​:32PM -0800, James E Keenan via RT wrote​:

On Tue Nov 08 14​:37​:05 2011, b_jonas wrote​:

This command gives an unexpected result​:

$ perl -wE 'say scalar(($_x, $_y) = split "/",
"one/two/three/four/five");'
3

One would naively think it should return 5, just like this
command​:

$ perl -wE 'say scalar((@​_x) = split "/",
"one/two/three/four/five");'
5

But we also need to take into account the documentation for the
'scalar'
function (perldoc -f scalar)​:

#####
Because "scalar" is a unary operator, if you accidentally use a
parenthesized list for the EXPR, this behaves as a scalar comma
expression, evaluating all but the last element in void context
and returning the final element evaluated in scalar context.
This is seldom what you want.
#####

That paragraph is not relevant here. The argument to scalar in the
first
example is not a parenthesized list; it is a list assignment. A list
assignment in scalar context returns the number of elements on its
right-hand side.

My hunch is that in your first case above, the "final element
evaluated
in scalar context" would be '3', the number of elements in ( qw|
three
four five | ).

No, it's 3, the number of elements in ( qw| one two three/four/five |
).

perldoc -f split

The LIMIT parameter can be used to split a line partially

  \($login\, $passwd\, $remainder\) = split\(/​:/\, $\_\, 3\);

When assigning to a list, if LIMIT is omitted, or zero, Perl
supplies a LIMIT one larger than the number of variables in
the list, to avoid unnecessary work. For the list above LIMIT
would have been 4 by default.

To get 5 instead, specify a limit of -1​:

$ perl -wE 'say scalar(($_x, $_y) = split "/",
"one/two/three/four/five", -1);'
5

This is not a bug.

It’s a wishlist item.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Dec 6, 2011

From ambrus@math.bme.hu

On Tue, Dec 6, 2011 at 3​:43 AM, Father Chrysostomos via RT
<perlbug-followup@​perl.org> wrote​:

On Mon Dec 05 18​:33​:01 2011, Ronald J Kimball <rjk@​tamias.net> wrote​:

perldoc -f split

  The LIMIT parameter can be used to split a line partially

      ($login, $passwd, $remainder) = split(/​:/, $_, 3);

  When assigning to a list, if LIMIT is omitted, or zero, Perl
  supplies a LIMIT one larger than the number of variables in
  the list, to avoid unnecessary work.  For the list above LIMIT
  would have been 4 by default.

To get 5 instead, specify a limit of -1​:

$ perl -wE 'say scalar(($_x, $_y) = split "/",
"one/two/three/four/five", -1);'
5

This is not a bug.

It’s a wishlist item.

Agreed with Father Chrysostomos. It's not a definite bug, but it's a
wishlist item, and I meant to imply so in my original report.

Ambrus

@p5pRT
Copy link
Author

p5pRT commented Nov 12, 2013

From ambrus@math.bme.hu

See also ticket #118879 .

@p5pRT
Copy link
Author

p5pRT commented Nov 12, 2013

From [Unknown Contact. See original ticket]

See also ticket #118879 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants