Perl / perl5

đŸȘ The Perl programming language
https://dev.perl.org/perl5/
Other
1.93k stars 552 forks source link

bug or wrong doc for 'foreach $lexical' #7224

Open p5pRT opened 20 years ago

p5pRT commented 20 years ago

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

Searchable as RT28396$

p5pRT commented 20 years ago

From @hfuru

Created by @hfuru

About `foreach $var (...)'\, the perlsyn manual page says\,

  If the variable was previously declared with "my"\, it uses   that variable instead of the global one\,

That is not true. It creates a new lexical variable for the loop with the same name as the outside variable\, exactly as if one had written `foreach my $var'. If it was the same variable\, functions outside the loop would see the loop variable\, but they don't. They see the "my" variable which was declared outside the loop. I suppose that's what you mean with this addition to the above text​:

  but it's still localized to the loop.

but that does not really make sense. That sounds like the value of the "outer" lexical variable would be saved\, and restored after the loop. That's how it works with non-lexical variables.

  my $var = "original value";   foreach $var ("loop-value") {   print "foreach​: $var\, ";   f();   }   print "end​: $var\n";   sub f { print "function​: $var\n"; } -->   foreach​: loop-value\, function​: original value   end​: original value

BTW\, I think this is a misfeature which should get a warning. If one has such a loop which intends the variable to be global\, inserting a `my' previously in the code silently breaks the loop even though that new `my' variable isn't actually used in the loop. And there is no need for this feature since one can just say `foreach my $var' instead of `foreach $var'.

Perl Info ``` Flags: category=docs severity=medium Site configuration information for perl v5.8.0: Configured by bhcompile at Wed Aug 13 11:45:59 EDT 2003. Summary of my perl5 (revision 5.0 version 8 subversion 0) configuration: Platform: osname=linux, osvers=2.4.21-1.1931.2.382.entsmp, archname=i386-linux-thread-multi uname='linux stripples.devel.redhat.com 2.4.21-1.1931.2.382.entsmp #1 smp wed aug 6 17:18:52 edt 2003 i686 i686 i386 gnulinux ' config_args='-des -Doptimize=-O2 -g -pipe -march=i386 -mcpu=i686 -Dmyhostname=localhost -Dperladmin=root@localhost -Dcc=gcc -Dcf_by=Red Hat, Inc. -Dinstallprefix=/usr -Dprefix=/usr -Darchname=i386-linux -Dvendorprefix=/usr -Dsiteprefix=/usr -Dotherlibdirs=/usr/lib/perl5/5.8.0 -Duseshrplib -Dusethreads -Duseithreads -Duselargefiles -Dd_dosuid -Dd_semctl_semun -Di_db -Ui_ndbm -Di_gdbm -Di_shadow -Di_syslog -Dman3ext=3pm -Duseperlio -Dinstallusrbinperl -Ubincompat5005 -Uversiononly -Dpager=/usr/bin/less -isr' hint=recommended, useposix=true, d_sigaction=define usethreads=define use5005threads=undef 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='gcc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm', optimize='-O2 -g -pipe -march=i386 -mcpu=i686', cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -I/usr/local/include -I/usr/include/gdbm' ccversion='', gccversion='3.2.2 20030222 (Red Hat Linux 3.2.2-5)', gccosandvers='' intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12 ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8 alignbytes=4, prototype=define Linker and Libraries: ld='gcc', ldflags =' -L/usr/local/lib' libpth=/usr/local/lib /lib /usr/lib libs=-lnsl -lgdbm -ldb -ldl -lm -lpthread -lc -lcrypt -lutil perllibs=-lnsl -ldl -lm -lpthread -lc -lcrypt -lutil libc=/lib/libc-2.3.2.so, so=so, useshrplib=true, libperl=libperl.so gnulibc_version='2.3.2' Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-rdynamic -Wl,-rpath,/usr/lib/perl5/5.8.0/i386-linux-thread-multi/CORE' cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib' Locally applied patches: MAINT18379 @INC for perl v5.8.0: /usr/lib/perl5/5.8.0/i386-linux-thread-multi /usr/lib/perl5/5.8.0 /usr/lib/perl5/site_perl/5.8.0/i386-linux-thread-multi /usr/lib/perl5/site_perl/5.8.0 /usr/lib/perl5/site_perl /usr/lib/perl5/vendor_perl/5.8.0/i386-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.0 /usr/lib/perl5/vendor_perl /usr/lib/perl5/5.8.0/i386-linux-thread-multi /usr/lib/perl5/5.8.0 . Environment for perl v5.8.0: HOME=/usit/saruman/gt-u1/hbf LANG (unset) LANGUAGE (unset) LC_CTYPE=no_NO LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/usr/bin:/usit/saruman/gt-u1/hbf/bin:/usit/saruman/gt-u1/hbf/bin/linux:/local/bin:/local/gnu/bin:/local/sbin:/usr/bin/X11:/usr/X11R6/bin:/usr/bin:/bin:/usr/games PERL_BADLANG (unset) SHELL=/local/gnu/bin/bash ```
p5pRT commented 12 years ago

From @jkeenan

On Thu Apr 08 21​:35​:31 2004\, h.b.furuseth@​usit.uio.no wrote​:

About `foreach $var (...)'\, the perlsyn manual page says\,

If the variable was previously declared with "my"\, it uses
that variable instead of the global one\,

That is not true. It creates a new lexical variable for the loop with the same name as the outside variable\, exactly as if one had written `foreach my $var'. If it was the same variable\, functions outside the loop would see the loop variable\, but they don't. They see the "my" variable which was declared outside the loop. I suppose that's what you mean with this addition to the above text​:

but it's still localized to the loop\.

but that does not really make sense. That sounds like the value of the "outer" lexical variable would be saved\, and restored after the loop. That's how it works with non-lexical variables.

my $var = "original value";
foreach $var \("loop\-value"\) \{
    print "foreach​: $var\, ";
    f\(\);
\}
print "end​: $var\\n";
sub f \{ print "function​: $var\\n"; \}

--> foreach​: loop-value\, function​: original value end​: original value

While reviewing older tickets\, I have read this several times. Each time I read it\, I tend to believe it.

But then\, when I go and read 'perldoc perlsyn' (the section on "Foreach Loops")\, I'm perfectly fine with what I read *there*. There's a final sentence in that paragraph that helps clarify things for me​: "This implicit localization occurs *only* in a 'foreach' loop."

So I don't think there's a bug here\, and the current documentation makes sense to me with respect to the poster's example above.

What do other people think?

Thank you very much. Jim Keenan

BTW\, I think this is a misfeature which should get a warning. If one has such a loop which intends the variable to be global\, inserting a `my' previously in the code silently breaks the loop even though that new `my' variable isn't actually used in the loop. And there is no need for this feature since one can just say `foreach my $var' instead of `foreach $var'.

[Please do not change anything below this line] ----------------------------------------------------------------- --- Flags​: category=docs severity=medium --- Site configuration information for perl v5.8.0​:

Configured by bhcompile at Wed Aug 13 11​:45​:59 EDT 2003.

Summary of my perl5 (revision 5.0 version 8 subversion 0) configuration​: Platform​: osname=linux\, osvers=2.4.21-1.1931.2.382.entsmp\, archname=i386- linux-thread-multi uname='linux stripples.devel.redhat.com 2.4.21-1.1931.2.382.entsmp #1 smp wed aug 6 17​:18​:52 edt 2003 i686 i686 i386 gnulinux ' config_args='-des -Doptimize=-O2 -g -pipe -march=i386 -mcpu=i686 -Dmyhostname=localhost -Dperladmin=root@​localhost -Dcc=gcc -Dcf_by=Red Hat\, Inc. -Dinstallprefix=/usr -Dprefix=/usr -Darchname=i386-linux -Dvendorprefix=/usr -Dsiteprefix=/usr -Dotherlibdirs=/usr/lib/perl5/5.8.0 -Duseshrplib -Dusethreads -Duseithreads -Duselargefiles -Dd_dosuid -Dd_semctl_semun -Di_db -Ui_ndbm -Di_gdbm -Di_shadow -Di_syslog -Dman3ext=3pm -Duseperlio -Dinstallusrbinperl -Ubincompat5005 -Uversiononly -Dpager=/usr/bin/less -isr' hint=recommended\, useposix=true\, d_sigaction=define usethreads=define use5005threads=undef 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='gcc'\, ccflags ='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm'\, optimize='-O2 -g -pipe -march=i386 -mcpu=i686'\, cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -I/usr/local/include -I/usr/include/gdbm' ccversion=''\, gccversion='3.2.2 20030222 (Red Hat Linux 3.2.2-5)'\, gccosandvers='' intsize=4\, longsize=4\, ptrsize=4\, doublesize=8\, byteorder=1234 d_longlong=define\, longlongsize=8\, d_longdbl=define\, longdblsize=12 ivtype='long'\, ivsize=4\, nvtype='double'\, nvsize=8\, Off_t='off_t'\, lseeksize=8 alignbytes=4\, prototype=define Linker and Libraries​: ld='gcc'\, ldflags =' -L/usr/local/lib' libpth=/usr/local/lib /lib /usr/lib libs=-lnsl -lgdbm -ldb -ldl -lm -lpthread -lc -lcrypt -lutil perllibs=-lnsl -ldl -lm -lpthread -lc -lcrypt -lutil libc=/lib/libc-2.3.2.so\, so=so\, useshrplib=true\, libperl=libperl.so gnulibc_version='2.3.2' Dynamic Linking​: dlsrc=dl_dlopen.xs\, dlext=so\, d_dlsymun=undef\, ccdlflags='- rdynamic -Wl\,-rpath\,/usr/lib/perl5/5.8.0/i386-linux-thread-multi/CORE' cccdlflags='-fPIC'\, lddlflags='-shared -L/usr/local/lib'

Locally applied patches​: MAINT18379

--- @​INC for perl v5.8.0​: /usr/lib/perl5/5.8.0/i386-linux-thread-multi /usr/lib/perl5/5.8.0 /usr/lib/perl5/site_perl/5.8.0/i386-linux-thread-multi /usr/lib/perl5/site_perl/5.8.0 /usr/lib/perl5/site_perl /usr/lib/perl5/vendor_perl/5.8.0/i386-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.0 /usr/lib/perl5/vendor_perl /usr/lib/perl5/5.8.0/i386-linux-thread-multi /usr/lib/perl5/5.8.0 .

--- Environment for perl v5.8.0​: HOME=/usit/saruman/gt-u1/hbf LANG (unset) LANGUAGE (unset) LC_CTYPE=no_NO LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/usr/bin​:/usit/saruman/gt-u1/hbf/bin​:/usit/saruman/gt-

u1/hbf/bin/linux​:/local/bin​:/local/gnu/bin​:/local/sbin​:/usr/bin/X11​:/usr/X11R6/bin​:/usr/bin​:/bin​:/usr/games PERL_BADLANG (unset) SHELL=/local/gnu/bin/bash

p5pRT commented 12 years ago

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

p5pRT commented 12 years ago

From @cpansprout

On Sat Dec 17 20​:02​:40 2011\, jkeenan wrote​:

On Thu Apr 08 21​:35​:31 2004\, h.b.furuseth@​usit.uio.no wrote​:

About `foreach $var (...)'\, the perlsyn manual page says\,

If the variable was previously declared with "my"\, it uses
that variable instead of the global one\,

That is not true. It creates a new lexical variable for the loop with the same name as the outside variable\, exactly as if one had written `foreach my $var'. If it was the same variable\, functions outside the loop would see the loop variable\, but they don't. They see the "my" variable which was declared outside the loop. I suppose that's what you mean with this addition to the above text​:

but it's still localized to the loop\.

but that does not really make sense. That sounds like the value of the "outer" lexical variable would be saved\, and restored after the loop. That's how it works with non-lexical variables.

my $var = "original value";
foreach $var \("loop\-value"\) \{
    print "foreach​: $var\, ";
    f\(\);
\}
print "end​: $var\\n";
sub f \{ print "function​: $var\\n"; \}

--> foreach​: loop-value\, function​: original value end​: original value

While reviewing older tickets\, I have read this several times. Each time I read it\, I tend to believe it.

But then\, when I go and read 'perldoc perlsyn' (the section on "Foreach Loops")\, I'm perfectly fine with what I read *there*. There's a final sentence in that paragraph that helps clarify things for me​: "This implicit localization occurs *only* in a 'foreach' loop."

So I don't think there's a bug here\, and the current documentation makes sense to me with respect to the poster's example above.

What do other people think?

I think this is a can of worms I don’t want to open. :-(

It makes me wonder​: If we introduce lexical aliases through lvalue references\, then which $x will the function see?

my $x = 3; my $y = 4; my $func = sub { print "$x\n"; }; \$x = \$y; &$func;

I think the original poster has a point. This doesn’t do what the documentation says​:

$ perl5.15.5 -le 'my $x = 3; my $sub = sub { print $x }; for $x (4){&$sub}' 3

--

Father Chrysostomos

p5pRT commented 12 years ago

From @cpansprout

On Sat Dec 17 23​:14​:17 2011\, sprout wrote​:

I think the original poster has a point. This doesn’t do what the documentation says​:

$ perl5.15.5 -le 'my $x = 3; my $sub = sub { print $x }; for $x (4){&$sub}' 3

It works for our variables​:

perl -le 'our $x; $sub = sub { print $x }; for $x(4) { &$sub }' 4

--

Father Chrysostomos

p5pRT commented 12 years ago

From @druud62

On 2011-12-18 05​:02\, James E Keenan via RT wrote​:

But then\, when I go and read 'perldoc perlsyn' (the section on "Foreach Loops")\, I'm perfectly fine with what I read *there*. There's a final sentence in that paragraph that helps clarify things for me​: "This implicit localization occurs *only* in a 'foreach' loop."

So I don't think there's a bug here\, and the current documentation makes sense to me with respect to the poster's example above.

What do other people think?

I don't like the implicit localization.

perl -wle '   my $i = 42;   for $i ( 1 .. 2 ) { print $i }   print $i; ' 1 2 42

I consider this magic-for-magic-only​:

perl -wle '   $_ = 0;   print;   for ( 1 .. 2 ) { print }   print;   print for 3 .. 4;   print; ' 0 1 2 0 3 4 0

(ok\, not for magic only\, good (and bad) for golfing too)

-- Ruud