Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Perl: porters

[perl #54974] Strange map {} Behavior When Returning Two Values

 

 

Perl porters RSS feed   Index | Next | Previous | View Threaded


perlbug-followup at perl

May 28, 2008, 12:36 PM

Post #1 of 12 (664 views)
Permalink
[perl #54974] Strange map {} Behavior When Returning Two Values

On Wed May 28 10:55:59 2008, david [at] kineticode wrote:
> On May 28, 2008, at 10:08, A. Pagaltzis via RT wrote:
> > Because Perl thinks you are constructing an anonymous hash.
> > If you disambiguate, it figures it out:
> >
> > my @a = map {; "--$_" => $_ } @ARGV;
> >
> > Note the semicolon.
>
> Would it not also think that it was an anonymous hash when I
> used the concatenation, as well?

It should, but apparently using a more complex expression makes
the parser reconsider its commitment to the hash constructor
interpretation of the curly braces.

Really this should be decided based on whether the closing brace
is followed by a comma or not, so in some sense this is certainly
a bug. But my understanding is that the syntactic ambiguity of
curly braces in Perl is difficult to handle in perl’s ultimately
yacc-derived (but heavily mutated) parser, which uses a limited
lookahead for curlies to work around the fact that this style of
parser strongly favours tokens with only a single meaning. In
practice, the heuristic works most of the time and the
disambiguation cues are easy to employ.

(You can equivalently disambiguate a hash constructor that gets
misparsed as a block by prepending a unary plus: `+{ ... }`.
Within such a block, statements are always a compile error.)

Someone else will have to tell you whether this is a WONTFIX tho.

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


perlbug-followup at perl

May 28, 2008, 9:22 AM

Post #2 of 12 (634 views)
Permalink
[perl #54974] Strange map {} Behavior When Returning Two Values [In reply to]

# New Ticket Created by David Wheeler
# Please include the string: [perl #54974]
# in the subject line of all future correspondence about this issue.
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=54974 >


perlbug,

This is a bug report for perl from david [at] kineticode,
generated with the help of perlbug 1.36 running under perl 5.10.0.


-----------------------------------------------------------------


When I run this code:

my @a = map { "--$_" => $_ } @ARGV;

I get this compile-time error:

Not enough arguments for map at /Users/david/bin/try line 6, near "} @ARGV"
syntax error at /Users/david/bin/try line 6, near "} @ARGV"
Execution of /Users/david/bin/try aborted due to compilation errors.

When I change the map to:

my @a = map { '--' . $_ => $_ } @ARGV;

It works. The only difference is using concatentation instead of the double-quoted string "--$_".

Curiously, I don't get the compile-time error for this code:

my @a = map { "--$_" } @ARGV;

So it seems to be something about returning two values from the map sub.

FWIW, I get a similar error with Perl 5.8.8:

syntax error at /Users/david/bin/try line 6, near "} @ARGV"
Execution of /Users/david/bin/try aborted due to compilation errors.

I'm fine to use the concatenation workaround, but it seems pretty bizarre, and so worth reporting.

Thanks!

David

-----------------------------------------------------------------
---
Flags:
category=core
severity=low
---
Site configuration information for perl 5.10.0:

Configured by david at Mon Apr 14 12:06:56 PDT 2008.

Summary of my perl5 (revision 5 version 10 subversion 0) configuration:
Platform:
osname=darwin, osvers=9.2.2, archname=darwin-2level
uname='darwin benedict.local 9.2.2 darwin kernel version 9.2.2: tue mar 4 21:17:34 pst 2008; root:xnu-1228.4.31~1release_i386 i386 '
config_args='-des -Duseshrplib -Dperladmin=david [at] kineticode -Dcf_email=david [at] kineticode'
hint=recommended, useposix=true, d_sigaction=define
useithreads=undef, usemultiplicity=undef
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 -no-cpp-precomp -fno-strict-aliasing -pipe -I/usr/local/include',
optimize='-O3',
cppflags='-no-cpp-precomp -fno-common -DPERL_DARWIN -no-cpp-precomp -fno-strict-aliasing -pipe -I/usr/local/include'
ccversion='', gccversion='4.0.1 (Apple Inc. build 5465)', 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 =' -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=true, libperl=libperl.dylib
gnulibc_version=''
Dynamic Linking:
dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' '
cccdlflags=' ', lddlflags=' -bundle -undefined dynamic_lookup -L/usr/local/lib'

Locally applied patches:


---
@INC for perl 5.10.0:
/usr/local/lib/perl5/5.10.0/darwin-2level
/usr/local/lib/perl5/5.10.0
/usr/local/lib/perl5/site_perl/5.10.0/darwin-2level
/usr/local/lib/perl5/site_perl/5.10.0
.

---
Environment for perl 5.10.0:
DYLD_LIBRARY_PATH (unset)
HOME=/Users/david
LANG=en_US.UTF-8
LANGUAGE (unset)
LD_LIBRARY_PATH (unset)
LOGDIR (unset)
PATH=/opt/local/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/Developer/Tools:/Users/david/bin:/usr/local/pgsql/bin:/usr/local/mysql/bin:/usr/X11/bin
PERL_BADLANG (unset)
SHELL=/bin/zsh


perlbug-comment at perl

May 28, 2008, 10:10 AM

Post #3 of 12 (637 views)
Permalink
[perl #54974] Strange map {} Behavior When Returning Two Values [In reply to]

On Wed May 28 09:22:22 2008, david [at] kineticode wrote:
> When I run this code:
>
> my @a = map { "--$_" => $_ } @ARGV;
>
> I get this compile-time error:
>
> Not enough arguments for map at /Users/david/bin/try line 6, near "}
> @ARGV"
> syntax error at /Users/david/bin/try line 6, near "} @ARGV"
> Execution of /Users/david/bin/try aborted due to compilation errors.

Because Perl thinks you are constructing an anonymous hash. If you
disambiguate, it figures it out:

my @a = map {; "--$_" => $_ } @ARGV;

Note the semicolon.

(Pardon the double-submit, but I forgot to CC p5p on the first go.)


rgarciasuarez at gmail

May 29, 2008, 1:42 AM

Post #4 of 12 (631 views)
Permalink
Re: [perl #54974] Strange map {} Behavior When Returning Two Values [In reply to]

2008/5/28 A. Pagaltzis via RT <perlbug-followup [at] perl>:
> Really this should be decided based on whether the closing brace
> is followed by a comma or not, so in some sense this is certainly
> a bug. But my understanding is that the syntactic ambiguity of
> curly braces in Perl is difficult to handle in perl's ultimately
> yacc-derived (but heavily mutated) parser, which uses a limited
> lookahead for curlies to work around the fact that this style of
> parser strongly favours tokens with only a single meaning. In
> practice, the heuristic works most of the time and the
> disambiguation cues are easy to employ.

Perl's parser is strictly a LALR(1) yacc-generated parser -- not a
"havily mutated" thingy. That means that it uses only one token of
lookahead, and that detecting anything after a closing brace is
impossible.

The smoke and mirrors are strictly kept in the tokenizer, which is
stateful, contrary to most classical tokenizers (like the ones lex
generates).


pagaltzis at gmx

May 29, 2008, 3:12 AM

Post #5 of 12 (634 views)
Permalink
Re: [perl #54974] Strange map {} Behavior When Returning Two Values [In reply to]

* Rafael Garcia-Suarez <rgarciasuarez [at] gmail> [2008-05-29 10:45]:
> Perl's parser is strictly a LALR(1) yacc-generated parser --
> not a "havily mutated" thingy. That means that it uses only one
> token of lookahead, and that detecting anything after a closing
> brace is impossible.
>
> The smoke and mirrors are strictly kept in the tokenizer, which
> is stateful, contrary to most classical tokenizers (like the
> ones lex generates).

Yes, the tokeniser is what I had in mind.

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


h.m.brand at xs4all

May 29, 2008, 3:55 AM

Post #6 of 12 (636 views)
Permalink
Re: [perl #54974] Strange map {} Behavior When Returning Two Values [In reply to]

On Wed, 28 May 2008 09:22:23 -0700, David Wheeler (via RT)
<perlbug-followup [at] perl> wrote:

> When I run this code:
>
> my @a = map { "--$_" => $_ } @ARGV;
>
> I get this compile-time error:
>
> Not enough arguments for map at /Users/david/bin/try line 6, near "} @ARGV"
> syntax error at /Users/david/bin/try line 6, near "} @ARGV"
> Execution of /Users/david/bin/try aborted due to compilation errors.

Enough explanation has already been passed back

$ perl -wle'my@a=map{"--$_"=>$_}@ARGV;print"(@a)"' foo bar
Not enough arguments for map at -e line 1, near "}@ARGV"
syntax error at -e line 1, near "}@ARGV"
Execution of -e aborted due to compilation errors.

using a semi-colon
$ perl -wle'my@a=map{;"--$_"=>$_}@ARGV;print"(@a)"' foo bar
(--foo foo --bar bar)

using parens
$ perl -wle'my@a=map{("--$_"=>$_)}@ARGV;print"(@a)"' foo bar
(--foo foo --bar bar)

using a unary +
$ perl -wle'my@a=map{+"--$_"=>$_}@ARGV;print"(@a)"' foo bar
(--foo foo --bar bar)

using catenation
$ perl -wle'my@a=map{"--".$_=>$_}@ARGV;print"(@a)"' foo bar
(--foo foo --bar bar)

I personally think that using parens here to disambuigate is the most
verbose option without adding unexplainable line noise

--
H.Merijn Brand Amsterdam Perl Mongers (http://amsterdam.pm.org/)
using & porting perl 5.6.2, 5.8.x, 5.10.x on HP-UX 10.20, 11.00, 11.11,
& 11.23, SuSE 10.1 & 10.2, AIX 5.2, and Cygwin. http://qa.perl.org
http://mirrors.develooper.com/hpux/ http://www.test-smoke.org
http://www.goldmark.org/jeff/stupid-disclaimers/


pagaltzis at gmx

May 29, 2008, 6:16 AM

Post #7 of 12 (630 views)
Permalink
Re: [perl #54974] Strange map {} Behavior When Returning Two Values [In reply to]

* H.Merijn Brand <h.m.brand [at] xs4all> [2008-05-29 13:00]:
> using a semi-colon
> $ perl -wle'my@a=map{;"--$_"=>$_}@ARGV;print"(@a)"' foo bar
> (--foo foo --bar bar)
>
> using parens
> $ perl -wle'my@a=map{("--$_"=>$_)}@ARGV;print"(@a)"' foo bar
> (--foo foo --bar bar)
>
> using a unary +
> $ perl -wle'my@a=map{+"--$_"=>$_}@ARGV;print"(@a)"' foo bar
> (--foo foo --bar bar)
>
> using catenation
> $ perl -wle'my@a=map{"--".$_=>$_}@ARGV;print"(@a)"' foo bar
> (--foo foo --bar bar)
>
> I personally think that using parens here to disambuigate is
> the most verbose option without adding unexplainable line noise

Which in my mind makes it the least desirable, since that makes
it “obviously” superfluous and therefore the most likely to be
removed by some overeager maintainer. The semicolon, OTOH, is so
unusual that it is much more obviously intentional, even if the
maintainer who discovers it doesn’t know what it’s there for. It
probably won’t prevent them from removing it, but I would expect
that after the code breaks they will conclude that the semicolon
was put there purposely to prevent that error. With parens, in
contrast, it seems more likely to me that the maintainer will
think the code worked just by accident because the previous
programmer wrote it in a peculiar style with no particular
intent.

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


davidnicol at gmail

May 29, 2008, 8:50 AM

Post #8 of 12 (618 views)
Permalink
Re: [perl #54974] Strange map {} Behavior When Returning Two Values [In reply to]

I like the parentheses version because whenever I write a function
that returns multiple results I put them in parentheses. Maybe I
don't have to, but I do, so the parentheses version is how I would
have written it.


abigail at abigail

May 30, 2008, 7:27 AM

Post #9 of 12 (608 views)
Permalink
Re: [perl #54974] Strange map {} Behavior When Returning Two Values [In reply to]

On Thu, May 29, 2008 at 03:16:31PM +0200, Aristotle Pagaltzis wrote:
> * H.Merijn Brand <h.m.brand [at] xs4all> [2008-05-29 13:00]:
> > using a semi-colon
> > $ perl -wle'my@a=map{;"--$_"=>$_}@ARGV;print"(@a)"' foo bar
> > (--foo foo --bar bar)
> >
> > using parens
> > $ perl -wle'my@a=map{("--$_"=>$_)}@ARGV;print"(@a)"' foo bar
> > (--foo foo --bar bar)
> >
> > using a unary +
> > $ perl -wle'my@a=map{+"--$_"=>$_}@ARGV;print"(@a)"' foo bar
> > (--foo foo --bar bar)
> >
> > using catenation
> > $ perl -wle'my@a=map{"--".$_=>$_}@ARGV;print"(@a)"' foo bar
> > (--foo foo --bar bar)
> >
> > I personally think that using parens here to disambuigate is
> > the most verbose option without adding unexplainable line noise
>
> Which in my mind makes it the least desirable, since that makes
> it ???obviously??? superfluous and therefore the most likely to be
> removed by some overeager maintainer. The semicolon, OTOH, is so
> unusual that it is much more obviously intentional, even if the
> maintainer who discovers it doesn???t know what it???s there for. It
> probably won???t prevent them from removing it, but I would expect
> that after the code breaks they will conclude that the semicolon
> was put there purposely to prevent that error. With parens, in
> contrast, it seems more likely to me that the maintainer will
> think the code worked just by accident because the previous
> programmer wrote it in a peculiar style with no particular
> intent.


I guess it's matter of style, but I prefer the parenthesis as well. The
semi-colon is unual enough that it mystefies many people. The overeager
maintainer who removes the parenthesis will be left code that doesn't
compile, let alone pass a test suite. I'm not so worried about that;
it'll be a simple delete 2 chars, compile, undo cycle. Worse would be
a maintainer that wastes half a day what the hell the semi-colon is for.


Abigail


gbarr at pobox

May 30, 2008, 5:05 PM

Post #10 of 12 (600 views)
Permalink
Re: [perl #54974] Strange map {} Behavior When Returning Two Values [In reply to]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


On May 30, 2008, at 9:27 AM, Abigail wrote:

> On Thu, May 29, 2008 at 03:16:31PM +0200, Aristotle Pagaltzis wrote:
>> * H.Merijn Brand <h.m.brand [at] xs4all> [2008-05-29 13:00]:
>>> using a semi-colon
>>> $ perl -wle'my@a=map{;"--$_"=>$_}@ARGV;print"(@a)"' foo bar
>>> (--foo foo --bar bar)
>>>
>>> using parens
>>> $ perl -wle'my@a=map{("--$_"=>$_)}@ARGV;print"(@a)"' foo bar
>>> (--foo foo --bar bar)
>>>
>>> using a unary +
>>> $ perl -wle'my@a=map{+"--$_"=>$_}@ARGV;print"(@a)"' foo bar
>>> (--foo foo --bar bar)
>>>
>>> using catenation
>>> $ perl -wle'my@a=map{"--".$_=>$_}@ARGV;print"(@a)"' foo bar
>>> (--foo foo --bar bar)
>>>
>>> I personally think that using parens here to disambuigate is
>>> the most verbose option without adding unexplainable line noise
>>
>> Which in my mind makes it the least desirable, since that makes
>> it ???obviously??? superfluous and therefore the most likely to be
>> removed by some overeager maintainer. The semicolon, OTOH, is so
>> unusual that it is much more obviously intentional, even if the
>> maintainer who discovers it doesn???t know what it???s there for. It
>> probably won???t prevent them from removing it, but I would expect
>> that after the code breaks they will conclude that the semicolon
>> was put there purposely to prevent that error. With parens, in
>> contrast, it seems more likely to me that the maintainer will
>> think the code worked just by accident because the previous
>> programmer wrote it in a peculiar style with no particular
>> intent.
>
>
> I guess it's matter of style, but I prefer the parenthesis as
> well. The
> semi-colon is unual enough that it mystefies many people. The
> overeager
> maintainer who removes the parenthesis will be left code that doesn't
> compile, let alone pass a test suite. I'm not so worried about that;
> it'll be a simple delete 2 chars, compile, undo cycle. Worse would be
> a maintainer that wastes half a day what the hell the semi-colon is
> for.

It is also one of the documented examples where the docs discuss the
issue that started this thread

%hash = map { "\L$_", 1 } @array # perl guesses EXPR. wrong
%hash = map { +"\L$_", 1 } @array # perl guesses BLOCK. right
%hash = map { ("\L$_", 1) } @array # this also works
%hash = map { lc($_), 1 } @array # as does this.
%hash = map +( lc($_), 1 ), @array # this is EXPR and works!

Graham.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (Darwin)

iD8DBQFIQJZTR0BL4gbYw3QRAtKBAJ46jUPEdyv1xZWblpPFXNGnaysECQCgjw1U
uIcIbUhdpGdKRcmJvWPTDXw=
=U1eO
-----END PGP SIGNATURE-----


blgl at hagernas

May 31, 2008, 2:34 PM

Post #11 of 12 (595 views)
Permalink
Re: [perl #54974] Strange map {} Behavior When Returning Two Values [In reply to]

In article <60CB2FCC-7405-4026-8119-4F7851F5BBB8 [at] pobox>,
gbarr [at] pobox (Graham Barr) wrote:

> %hash = map +( lc($_), 1 ), @array # this is EXPR and works!

Add a note to perlop.pod about unary + being so utterly no-op that
it doesn't even force scalar context?


/Bo Lindbergh


abigail at abigail

May 31, 2008, 3:44 PM

Post #12 of 12 (595 views)
Permalink
Re: [perl #54974] Strange map {} Behavior When Returning Two Values [In reply to]

On Sat, May 31, 2008 at 11:34:22PM +0200, Bo Lindbergh wrote:
> In article <60CB2FCC-7405-4026-8119-4F7851F5BBB8 [at] pobox>,
> gbarr [at] pobox (Graham Barr) wrote:
>
> > %hash = map +( lc($_), 1 ), @array # this is EXPR and works!
>
> Add a note to perlop.pod about unary + being so utterly no-op that
> it doesn't even force scalar context?


Three quarters of the description of unary "+" is already dedicated
to describe exactly the situation above. Mentioning context doesn't
improve the current description, IMO. In fact, saying it doesn't force
scalar context will have some people assume it forces list context.



Abigail

Perl porters RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.