Perl / perl5

šŸŖ The Perl programming language
https://dev.perl.org/perl5/
Other
1.9k stars 540 forks source link

Some unary functions accept multiple arguments #11540

Open p5pRT opened 13 years ago

p5pRT commented 13 years ago

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

Searchable as RT96006$

p5pRT commented 13 years ago

From @cpansprout

perl56delta has this section​:

  Better syntax checks on parenthesized unary operators   Expressions such as​:

  print defined(&foo\,&bar\,&baz);   print uc("foo"\,"bar"\,"baz");   undef($foo\,&bar);

  used to be accidentally allowed in earlier versions\, and produced   unpredictable behaviour. Some produced ancillary warnings when used in   this way; others silently did the wrong thing.

  The parenthesized forms of most unary operators that expect a single   argument now ensure that they are not called with more than one   argument\, making the cases shown above syntax errors. The usual   behaviour of​:

  print defined &foo\, &bar\, &baz;   print uc "foo"\, "bar"\, "baz";   undef $foo\, &bar;

  remains unchanged. See perlop.

A few of unary functions survived\, though​:

prototype(1\,2\,3) evaluates 1 and 2 in void context\, using 3 (in scalar context) as its argument. Thatā€™s harmless\, although a bit surprising. eval() behaves the same way.

When called in list context readline and readpipe evaluate their arguments in list context\, and then pop the topmost item leaving everything else there\, in addition to the value intended to be returned.

In scalar context readline and readpipe act like prototype.

In dynamic context (determined at run-time; e.g.\, at the end of a sub) readline and readpipe propagate their context to *all* their arguments. So readpipe(foo()\,foo()) at the end of a subroutine makes both foo calls in scalar context if the subroutine is called in scalar context\, but calls the first foo in void context if readpipe can be determined at compile time to be in scalar context.

Here are some examples​:

$ perl -le'open my $foo\, "\<"\, \"bar"; print readline("baz"\,$foo)' bazbar

$ perl -le'open my $foo\, "\<"\, \"bar"; print "baz"\,$foo\,readline(sub{}->())' bazbar

Context of readlineā€™s operands​:

$ perl -le 'sub context { print qw[void scalar list][wantarray + defined wantarray] } readline(context\,context)' void void

which means that a function called in void context can return a value (the second readline would give bar\, not baz\, if get_fooā€™s retval were ignored)​:

$ perl -le 'open my $foo\, "\<"\, \"bar\nbaz"; sub get_foo {print qw[void scalar list][wantarray + defined wantarray]; $foo } readline(get_foo); print scalar readline $foo' void baz

$ perl -le 'sub context { print qw[void scalar list][wantarray + defined wantarray] } $x = readline(context\,context)' void scalar

$ perl -le 'sub context { print qw[void scalar list][wantarray + defined wantarray] } () = readline(context\,context)' list list

Context of readlineā€™s operands in dynamic context​:

$ perl -le 'sub context { print qw[void scalar list][wantarray + defined wantarray] } sub { readline(context\,context) }->()' void void

$ perl -le 'sub context { print qw[void scalar list][wantarray + defined wantarray] } $x = sub { readline(context\,context) }->()' scalar scalar

$ perl -le 'sub context { print qw[void scalar list][wantarray + defined wantarray] } () = sub { readline(context\,context) }->()' list list


Flags​:   category=core   severity=low


Site configuration information for perl 5.15.0​:

Configured by sprout at Thu Jun 16 05​:42​:17 PDT 2011.

Summary of my perl5 (revision 5 version 15 subversion 0) configuration​:   Snapshot of​: 00b4043708e2509400eff8f5e4cb870d388854d4   Platform​:   osname=darwin\, osvers=10.5.0\, archname=darwin-thread-multi-2level   uname='darwin pint.local 10.5.0 darwin kernel version 10.5.0​: fri nov 5 23​:20​:39 pdt 2010; root​:xnu-1504.9.17~1release_i386 i386 '   config_args='-de -Dusedevel -Duseithreads'   hint=recommended\, useposix=true\, d_sigaction=define   useithreads=define\, usemultiplicity=define   useperlio=define\, d_sfio=undef\, uselargefiles=define\, usesocks=undef   use64bitint=undef\, use64bitall=undef\, uselongdouble=undef   usemymalloc=n\, bincompat5005=undef   Compiler​:   cc='cc'\, ccflags ='-fno-common -DPERL_DARWIN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'\,   optimize='-O3'\,   cppflags='-fno-common -DPERL_DARWIN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'   ccversion=''\, gccversion='4.2.1 (Apple Inc. build 5664)'\, gccosandvers=''   intsize=4\, longsize=4\, ptrsize=4\, doublesize=8\, byteorder=1234   d_longlong=define\, longlongsize=8\, d_longdbl=define\, longdblsize=16   ivtype='long'\, ivsize=4\, nvtype='double'\, nvsize=8\, Off_t='off_t'\, lseeksize=8   alignbytes=8\, prototype=define   Linker and Libraries​:   ld='env MACOSX_DEPLOYMENT_TARGET=10.3 cc'\, ldflags =' -fstack-protector -L/usr/local/lib'   libpth=/usr/local/lib /usr/lib   libs=-ldbm -ldl -lm -lutil -lc   perllibs=-ldl -lm -lutil -lc   libc=/usr/lib/libc.dylib\, so=dylib\, useshrplib=false\, libperl=libperl.a   gnulibc_version=''   Dynamic Linking​:   dlsrc=dl_dlopen.xs\, dlext=bundle\, d_dlsymun=undef\, ccdlflags=' '   cccdlflags=' '\, lddlflags=' -bundle -undefined dynamic_lookup -L/usr/local/lib -fstack-protector'

Locally applied patches​:  


@​INC for perl 5.15.0​:   /usr/local/lib/perl5/site_perl/5.15.0/darwin-thread-multi-2level   /usr/local/lib/perl5/site_perl/5.15.0   /usr/local/lib/perl5/5.15.0/darwin-thread-multi-2level   /usr/local/lib/perl5/5.15.0   /usr/local/lib/perl5/site_perl   .


Environment for perl 5.15.0​:   DYLD_LIBRARY_PATH (unset)   HOME=/Users/sprout   LANG=en_US.UTF-8   LANGUAGE (unset)   LD_LIBRARY_PATH (unset)   LOGDIR (unset)   PATH=/usr/bin​:/bin​:/usr/sbin​:/sbin​:/usr/local/bin​:/usr/X11/bin​:/usr/local/bin   PERL_BADLANG (unset)   SHELL=/bin/bash

p5pRT commented 12 years ago

From @cpansprout

On Sun Jul 31 13​:54​:42 2011\, sprout wrote​:

perl56delta has this section​:

Better syntax checks on parenthesized unary operators Expressions such as​:

       print defined\(&foo\,&bar\,&baz\);
       print uc\("foo"\,"bar"\,"baz"\);
       undef\($foo\,&bar\);

   used to be accidentally allowed in earlier versions\, and

produced unpredictable behaviour. Some produced ancillary warnings when used in this way; others silently did the wrong thing.

   The parenthesized forms of most unary operators that expect a

single argument now ensure that they are not called with more than one argument\, making the cases shown above syntax errors. The usual behaviour of​:

       print defined &foo\, &bar\, &baz;
       print uc "foo"\, "bar"\, "baz";
       undef $foo\, &bar;

   remains unchanged\.  See perlop\.

A few of unary functions survived\, though​:

prototype(1\,2\,3) evaluates 1 and 2 in void context\, using 3 (in scalar context) as its argument. Thatā€™s harmless\, although a bit surprising. eval() behaves the same way.

Iā€™ve been thinking about this on and off for some time.

!($foo\, $bar) evaluates $foo in void context and $bar in scalar context. If we were to change that to ā€˜too many arguments for !ā€™\, we would have a lynch mob after us.

The same applies to not($foo\, $bar) and scalar($foo\, $bar).

So Iā€™ve been wondering why chr and getprotobynumber (for example) need to refuse more than one argument. How are these fundamentally different from not and scalar?

If I get a void warning when writing scalar(3\, foo())\, isnā€™t that sufficient for other ops as well?

Now\, there is one case where it makes sense to refuse more than one argument​: scalar lvalue context.

Iā€™m using the term lvalue in the broad sense of anything that goes through op_lvalue internally\, which means anything with a prototype containing \$\, \[$@​%&*] or \[$@​%*]\, or that parses as though it had such a prototype.

In the case of untie(%foo\,%bar)\, it is completely counterintuitive that %bar should be untied\, but not %foo. So in this case it makes sense to refuse more than one argument (which doesnā€™t currently happen).

What I propose we do is make built-in functions with a prototype (or effective prototype) of ($)\, (;$)\, (*)\, (;*) or (_) allow more than one argument\, but treat it as a single scalar expression (i.e.\, with a scalar comma); and make built-in functions with a(n effective) prototype of (\$)\, (\[$@​%*])\, etc. refuse more than one argument.

Now\, should the laxity regarding ($) apply to user-defined subroutines\, too?

--

Father Chrysostomos

p5pRT commented 12 years ago

From [Unknown Contact. See original ticket]

On Sun Jul 31 13​:54​:42 2011\, sprout wrote​:

perl56delta has this section​:

Better syntax checks on parenthesized unary operators Expressions such as​:

       print defined\(&foo\,&bar\,&baz\);
       print uc\("foo"\,"bar"\,"baz"\);
       undef\($foo\,&bar\);

   used to be accidentally allowed in earlier versions\, and

produced unpredictable behaviour. Some produced ancillary warnings when used in this way; others silently did the wrong thing.

   The parenthesized forms of most unary operators that expect a

single argument now ensure that they are not called with more than one argument\, making the cases shown above syntax errors. The usual behaviour of​:

       print defined &foo\, &bar\, &baz;
       print uc "foo"\, "bar"\, "baz";
       undef $foo\, &bar;

   remains unchanged\.  See perlop\.

A few of unary functions survived\, though​:

prototype(1\,2\,3) evaluates 1 and 2 in void context\, using 3 (in scalar context) as its argument. Thatā€™s harmless\, although a bit surprising. eval() behaves the same way.

Iā€™ve been thinking about this on and off for some time.

!($foo\, $bar) evaluates $foo in void context and $bar in scalar context. If we were to change that to ā€˜too many arguments for !ā€™\, we would have a lynch mob after us.

The same applies to not($foo\, $bar) and scalar($foo\, $bar).

So Iā€™ve been wondering why chr and getprotobynumber (for example) need to refuse more than one argument. How are these fundamentally different from not and scalar?

If I get a void warning when writing scalar(3\, foo())\, isnā€™t that sufficient for other ops as well?

Now\, there is one case where it makes sense to refuse more than one argument​: scalar lvalue context.

Iā€™m using the term lvalue in the broad sense of anything that goes through op_lvalue internally\, which means anything with a prototype containing \$\, \[$@​%&*] or \[$@​%*]\, or that parses as though it had such a prototype.

In the case of untie(%foo\,%bar)\, it is completely counterintuitive that %bar should be untied\, but not %foo. So in this case it makes sense to refuse more than one argument (which doesnā€™t currently happen).

What I propose we do is make built-in functions with a prototype (or effective prototype) of ($)\, (;$)\, (*)\, (;*) or (_) allow more than one argument\, but treat it as a single scalar expression (i.e.\, with a scalar comma); and make built-in functions with a(n effective) prototype of (\$)\, (\[$@​%*])\, etc. refuse more than one argument.

Now\, should the laxity regarding ($) apply to user-defined subroutines\, too?

--

Father Chrysostomos

p5pRT commented 12 years ago

@cpansprout - Status changed from 'new' to 'open'

p5pRT commented 12 years ago

From @ap

* Father Chrysostomos via RT \perlbug\-comment@&#8203;perl\.org [2012-05-12 21​:15]​:

!($foo\, $bar) evaluates $foo in void context and $bar in scalar context. If we were to change that to ā€˜too many arguments for !ā€™\, we would have a lynch mob after us.

The same applies to not($foo\, $bar) and scalar($foo\, $bar).

So Iā€™ve been wondering why chr and getprotobynumber (for example) need to refuse more than one argument. How are these fundamentally different from not and scalar?

If I get a void warning when writing scalar(3\, foo())\, isnā€™t that sufficient for other ops as well?

Iā€™ll turn your question on its head.

Is there any reason not to make `scalar` as strict as `chr`? What does relaxing the rules gain? Does it simplify any code\, either on the user or the interpreter side? As far as I can tell\, all you achieve is to change one error to another warning.

We have had a lot of cases where syntax improvements or alterations to accommodate new features have proven impossible or just extremely difficult because Perl syntax is so lax in many ways that all plausible options already had some meaning or other.

So all else being equal I would advocate more strictness over less\, as a rough rule of thumb.

Regards\, -- Aristotle Pagaltzis // \<http​://plasmasturm.org/>