develooper Front page | perl.perl5.porters | Postings from August 2009

[perl #68816] RE match variable scope

Thread Next
From:
perlbug-followup
Date:
August 27, 2009 01:15
Subject:
[perl #68816] RE match variable scope
Message ID:
rt-3.6.HEAD-2466-1251360575-725.68816-75-0@perl.org
# New Ticket Created by  ian.goodacre@xtra.co.nz 
# Please include the string:  [perl #68816]
# in the subject line of all future correspondence about this issue. 
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=68816 >


This is a bug report for perl from ian@alula.home.local,
generated with the help of perlbug 1.36 running under perl 5.10.0.


-----------------------------------------------------------------
[Pleas enter your report here]

perlre says:

       The numbered match variables ($1, $2, $3, etc.) and the related
       punctuation set ($+, $&, "$`", "$'", and $^N) are all dynamically
       scoped until the end of the enclosing block or until the next
       successful match, whichever comes first.  (See "Compound 
Statements" in
       perlsyn.)

       NOTE: Failed matches in Perl do not reset the match variables, which
       makes it easier to write code that tests for a series of more 
specific
       cases and remembers the best match.

In a foreach loop I expect that the BLOCK is entered, executed and 
exited once
in each iteration of the loop (with the possible exception of the redo loop
control command, which should be better defined to specify whether it causes
scope exit and entry).

Thus I expect that numbered match variables created within a loop BLOCK 
go out
of scope at the end of the iteration in which they were defined. If there is
no match in an iteration, I expect the loop variables will not be defined,
in which case it is ambiguous and should be documented whether dynamically
scoped numbered match variables defined in an outer scope are masked or not.


In the following, I expect '1' to be printed only in the first iteration

$ perl -wle 'for(1..3){/(1)/; print $1 // "undef"}'
1
1
1

I expect the presence of an empty continue block not to make any difference,
but in fact it does - it corrects the behavior.

$ perl -wle 'for(1..3){/(1)/; print $1 // "undef"}continue{}'
1
undef
undef



Consider also:

my $_ = '1';

/(.)/;

print "before: \$1 = $1\n";

for (2..4) {
    print "\$_ = $_\n";
    print "first:  \$1 = $1\n";
    /(3)/;
    print "second: \$1 = $1\n";
}

print "after: \$1 = $1\n";


Which produces

before: $1 = 1
$_ = 2
first:  $1 = 1
second: $1 = 1
$_ = 3
first:  $1 = 1
second: $1 = 3
$_ = 4
first:  $1 = 3
second: $1 = 3
after: $1 = 1


The $1 of the outer scope is visible within the loop BLOCK until the 
successful
match in the second iteration, after which the $1 of the outer scope is 
masked.
But the inner scope $1 continues to mask the outer scope $1 throughout 
the third
iteration, as if it didn't go out of scope when execution of the loop 
BLOCK was
completed at the end of the second iteration.


Note that the $1 of the outer scope does exist separately and is not merely
overwritten by the match within the loop. After the loop is finished it 
still
has its proper value.


Again, adding an empty continue BLOCK results in correct behavior:

my $_ = '1';

/(.)/;

print "before: \$1 = $1\n";

for (2..4) {
    print "\$_ = $_\n";
    print "first:  \$1 = $1\n";
    /(3)/;
    print "second: \$1 = $1\n";
} continue {}

print "after: \$1 = $1\n";


produces

before: $1 = 1
$_ = 2
first:  $1 = 1
second: $1 = 1
$_ = 3
first:  $1 = 1
second: $1 = 3
$_ = 4
first:  $1 = 1
second: $1 = 1
after: $1 = 1



Compare this also with

my $var = "outer";

print "before: $var\n";

for (1..3) {
    print "first:  $var\n";
    my $var = "inner $_" if(/2/);
    print "second: $var\n";
}

print "after:  $var\n";


which produces

before: outer
first:  outer
second:
first:  outer
second: inner 2
first:  outer
second:
after:  outer


In this case, as expected, the dynamically scoped $var of the inner scope
doesn't mask that of the outer scope before it is declared and the value
of the $var of the inner scope does not persist from one iteration to
the next even if the runtime effect of the initialization is prevented
by a conditional.


I think it would be better if the number match variables from a match
within a loop BLOCK behaved as they do when that loop  has an
empty continue BLOCK.

If there is a reason not to change this behavior then the behavior and
the reason for it should be prominently documented.



[Please do not change anything below this line]
-----------------------------------------------------------------
---
Flags:
    category=core
    severity=low
---
Site configuration information for perl 5.10.0:

Configured by ian at Sat Jul 18 17:25:15 NZST 2009.

Summary of my perl5 (revision 5 version 10 subversion 0) configuration:
  Platform:
    osname=linux, osvers=2.6.18-92.el5, archname=i686-linux-thread-multi
    uname='linux alula.home.local 2.6.18-92.el5 #1 smp tue jun 10 
18:49:47 edt 2008 i686 i686 i386 gnulinux '
    config_args=''
    hint=previous, 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 ='-D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing 
-pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 
-I/usr/include/gdbm',
    optimize='-O2',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing -pipe 
-I/usr/local/include -I/usr/include/gdbm -D_REENTRANT -D_GNU_SOURCE 
-fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE 
-D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm'
    ccversion='', gccversion='4.1.2 20080704 (Red Hat 4.1.2-44)', 
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='cc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lpthread -lc
    perllibs=-lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
    libc=/lib/libc-2.5.so, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version='2.5'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib'

Locally applied patches:


---
@INC for perl 5.10.0:
    /usr/local/lib/perl5/5.10.0/i686-linux-thread-multi
    /usr/local/lib/perl5/5.10.0
    /usr/local/lib/perl5/site_perl/5.10.0/i686-linux-thread-multi
    /usr/local/lib/perl5/site_perl/5.10.0
    .

---
Environment for perl 5.10.0:
    HOME=/home/ian
    LANG=en_NZ.UTF-8
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    
PATH=/usr/local/java/jdk/bin:/usr/local/java/ant/bin:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/Trolltech/Qt-4.4.3/bin:/home/ian/bin:/sbin
    PERLDOC_PAGER=less
    PERL_BADLANG (unset)
    SHELL=/bin/bash


Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About