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

(if|unless) ( local ... ) not undone #4370

Open
p5pRT opened this issue Sep 3, 2001 · 16 comments
Open

(if|unless) ( local ... ) not undone #4370

p5pRT opened this issue Sep 3, 2001 · 16 comments

Comments

@p5pRT
Copy link

p5pRT commented Sep 3, 2001

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

Searchable as RT7615$

@p5pRT
Copy link
Author

p5pRT commented Sep 3, 2001

From bwarnock@capita.com


Local variables declared in a conditional expression of a
conditional block are not restored at the end of scope.

$a = 10;
if (local $a = 1){
}
print $a; # Should be 10, not 1

Applies to local variables declared in 'if (expr)', 'unless(expr)',
and 'elsif (expr)'. Lexical variables are okay, as are local
variables in the conditional expression of a loop block.

Occurs in 5.005_03 through 5.7.2.



Flags​:
  category=core
  severity=low


Site configuration information for perl v5.6.1​:

Configured by bryan at Sat Jun 9 11​:24​:22 EDT 2001.

Summary of my perl5 (revision 5.0 version 6 subversion 1) configuration​:
  Platform​:
  osname=linux, osvers=2.4.3-20mdk, archname=i686-linux-64all-ld
  uname='linux wakko.idiocity.nut 2.4.3-20mdk #1 sun apr 15 23​:03​:10 cest
2001 i686 unknown '
  config_args=''
  hint=recommended, useposix=true, d_sigaction=define
  usethreads=undef use5005threads=undef useithreads=undef
usemultiplicity=undef
  useperlio=undef d_sfio=undef uselargefiles=define usesocks=undef
  use64bitint=define use64bitall=define uselongdouble=define
  Compiler​:
  cc='gcc', ccflags ='-DDEBUGGING -fno-strict-aliasing -D_LARGEFILE_SOURCE
-D_FILE_OFFSET_BITS=64',
  optimize='-g',
  cppflags='-DDEBUGGING -fno-strict-aliasing'
  ccversion='', gccversion='2.96 20000731 (Linux-Mandrake 8.0
2.96-0.48mdk)', gccosandvers=''
  intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=12345678
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
  ivtype='long long', ivsize=8, nvtype='long double', nvsize=12,
Off_t='off_t', lseeksize=8
  alignbytes=4, usemymalloc=n, prototype=define
  Linker and Libraries​:
  ld='gcc', ldflags =' -L/usr/local/lib'
  libpth=/usr/local/lib /lib /usr/lib
  libs=-lnsl -ldb -ldl -lm -lc -lcrypt -lutil
  perllibs=-lnsl -ldl -lm -lc -lcrypt -lutil
  libc=/lib/libc-2.2.2.so, so=so, useshrplib=false, libperl=libperl.a
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-rdynamic'
  cccdlflags='-fpic', lddlflags='-shared -L/usr/local/lib'

Locally applied patches​:


@​INC for perl v5.6.1​:
  /usr/local/lib/perl5/5.6.1/i686-linux-64all-ld
  /usr/local/lib/perl5/5.6.1
  /usr/local/lib/perl5/site_perl/5.6.1/i686-linux-64all-ld
  /usr/local/lib/perl5/site_perl/5.6.1
  /usr/local/lib/perl5/site_perl
  .


Environment for perl v5.6.1​:
  HOME=/home/bryan
  LANG=en
  LANGUAGE=en_US​:en
  LC_COLLATE=en_US
  LC_CTYPE=en_US
  LC_MESSAGES=en_US
  LC_MONETARY=en_US
  LC_NUMERIC=en_US
  LC_TIME=en_US
  LD_LIBRARY_PATH=/usr/lib
  LOGDIR (unset)

PATH=.​:/home/bryan/bin​:/usr/local/bin​:/bin​:/usr/bin​:/usr/X11R6/bin​:/sbin​:/us
r/sbin PERL_BADLANG (unset)
  SHELL=/bin/tcsh

@p5pRT
Copy link
Author

p5pRT commented Aug 26, 2005

From @smpeters

[bwarnock@​capita.com - Mon Sep 03 10​:43​:30 2001]​:

-----------------------------------------------------------------
Local variables declared in a conditional expression of a
conditional block are not restored at the end of scope.

$a = 10;
if (local $a = 1){
}
print $a; # Should be 10, not 1

Applies to local variables declared in 'if (expr)', 'unless(expr)',
and 'elsif (expr)'. Lexical variables are okay, as are local
variables in the conditional expression of a loop block.

This behavior has been fixed in bleadperl by not allowing it.

./perl rt_7615.pl
Can't localize lexical variable $a at rt_7615.pl line 4.

@p5pRT
Copy link
Author

p5pRT commented Aug 26, 2005

@smpeters - Status changed from 'open' to 'resolved'

@p5pRT
Copy link
Author

p5pRT commented Aug 26, 2005

From @tamias

On Fri, Aug 26, 2005 at 09​:06​:50AM -0700, Steve Peters via RT wrote​:

[bwarnock@​capita.com - Mon Sep 03 10​:43​:30 2001]​:

-----------------------------------------------------------------
Local variables declared in a conditional expression of a
conditional block are not restored at the end of scope.

$a = 10;
if (local $a = 1){
}
print $a; # Should be 10, not 1

Applies to local variables declared in 'if (expr)', 'unless(expr)',
and 'elsif (expr)'. Lexical variables are okay, as are local
variables in the conditional expression of a loop block.

This behavior has been fixed in bleadperl by not allowing it.

./perl rt_7615.pl
Can't localize lexical variable $a at rt_7615.pl line 4.

$a isn't a lexical variable in the example, so that doesn't fix it.

Ronald

@p5pRT
Copy link
Author

p5pRT commented Aug 26, 2005

From mjtg@cam.ac.uk

Steve Peters wrote

This behavior has been fixed in bleadperl by not allowing it.

./perl rt_7615.pl
Can't localize lexical variable $a at rt_7615.pl line 4.

No it hasn't. I suspect you did the wrong test - what's that
"lexical" doing in the error message?

When I try

perl5.8.6 -w
$a = 10;
if (local $a = 1){
}
print $a; # Should be 10, not 1
__END__
Found = in conditional, should be == at - line 2.
1

the bug is still present.

I presume this is another manifestation of the fact that a conditional
involves *two* scopes, one including the condition and one not.
Perl conflates them, with unfortunate results.

I presume the resaon for conflating them is efficiency.

Mike Guy

@p5pRT
Copy link
Author

p5pRT commented Aug 26, 2005

@smpeters - Status changed from 'resolved' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Aug 26, 2005

From @smpeters

[mjtg@​cam.ac.uk - Fri Aug 26 09​:47​:17 2005]​:

Steve Peters wrote

This behavior has been fixed in bleadperl by not allowing it.

./perl rt_7615.pl
Can't localize lexical variable $a at rt_7615.pl line 4.

No it hasn't. I suspect you did the wrong test - what's that
"lexical" doing in the error message?

When I try

perl5.8.6 -w
$a = 10;
if (local $a = 1){
}
print $a; # Should be 10, not 1
__END__
Found = in conditional, should be == at - line 2.
1

the bug is still present.

I presume this is another manifestation of the fact that a conditional
involves *two* scopes, one including the condition and one not.
Perl conflates them, with unfortunate results.

I presume the resaon for conflating them is efficiency.

Sorry, a C<my> crept into my code I was using for testing. So, it
appears at least lexical globals are fixed in blead, although
non-lexicals are still as broken as before. Ticket re-opened.

@p5pRT
Copy link
Author

p5pRT commented Aug 26, 2005

@smpeters - Status changed from 'open' to 'resolved'

@p5pRT p5pRT closed this as completed Aug 26, 2005
@p5pRT
Copy link
Author

p5pRT commented Aug 26, 2005

@smpeters - Status changed from 'resolved' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Sep 10, 2005

From @schwern

On Fri, Aug 26, 2005 at 09​:06​:50AM -0700, Steve Peters via RT wrote​:

$a = 10;
if (local $a = 1){
}
print $a; # Should be 10, not 1

Still busted in 5.8.6 and blead.

$ bleadperl -wle '$a = 10; if( local $a = 1 ) {} print $a'
Found = in conditional, should be == at -e line 1.
1
$ bleadperl -wle '$a = 10; if( my $a = 1 ) {} print $a'
Found = in conditional, should be == at -e line 1.
10

--
Michael G Schwern schwern@​pobox.com http​://www.pobox.com/~schwern
'All anyone gets in a mirror is themselves,' she said. 'But what you
gets in a good gumbo is everything.'
  -- "Witches Abroad" by Terry Prachett

@p5pRT
Copy link
Author

p5pRT commented May 27, 2012

From @jkeenan

On Sat Sep 10 14​:08​:31 2005, schwern wrote​:

On Fri, Aug 26, 2005 at 09​:06​:50AM -0700, Steve Peters via RT wrote​:

$a = 10;
if (local $a = 1){
}
print $a; # Should be 10, not 1

Still busted in 5.8.6 and blead.

$ bleadperl -wle '$a = 10; if( local $a = 1 ) {} print $a'
Found = in conditional, should be == at -e line 1.
1
$ bleadperl -wle '$a = 10; if( my $a = 1 ) {} print $a'
Found = in conditional, should be == at -e line 1.
10

And still busted in 5.16.0.

@p5pRT
Copy link
Author

p5pRT commented May 28, 2012

From @iabyn

On Sat, May 26, 2012 at 06​:10​:39PM -0700, James E Keenan via RT wrote​:

On Sat Sep 10 14​:08​:31 2005, schwern wrote​:

On Fri, Aug 26, 2005 at 09​:06​:50AM -0700, Steve Peters via RT wrote​:

$a = 10;
if (local $a = 1){
}
print $a; # Should be 10, not 1

Still busted in 5.8.6 and blead.

$ bleadperl -wle '$a = 10; if( local $a = 1 ) {} print $a'
Found = in conditional, should be == at -e line 1.
1
$ bleadperl -wle '$a = 10; if( my $a = 1 ) {} print $a'
Found = in conditional, should be == at -e line 1.
10

And still busted in 5.16.0.

The comparison to lexical vars is slightly misleading; its actually
lexical vars which are the more broken​: the scope of the visibility of the
'my' declaration doesn't match the scope of when the lexical is actually
freed​:

  sub DESTROY { warn "DESTROY(@​_)\n" }

  {
  $x = 1;
  if (my $x = bless []) {
  warn "in IF block​: $x\n";
  }
  warn "exited IF block​: $x\n";
  }
  warn "exited outer block​: $x\n";

  warn "----\n";

  {
  $a = 1;

  if (local $a = 2) {
  warn "in IF block​: $a\n";
  }
  warn "exited IF block​: $a\n";
  }
  warn "exited outer block​: $a\n";

which outputs​:

  in IF block​: main=ARRAY(0x235bde8)
  exited IF block​: 1
  DESTROY(main=ARRAY(0x235bde8))
  exited outer block​: 1
  ----
  in IF block​: 2
  exited IF block​: 2
  exited outer block​: 1

Here, the scope of when the lexical is freed and when the 'local' is
undone, is consistently at the end of the enclosing block, which could
arguably be viewed as correct; however the visibility of the lexical
*declaration* is only for the inner block.

--
"Do not dabble in paradox, Edward, it puts you in danger of fortuitous wit."
  -- Lady Croom, "Arcadia"

@p5pRT
Copy link
Author

p5pRT commented May 31, 2012

From @doy

On Sun, May 27, 2012 at 11​:22​:45PM +0100, Dave Mitchell wrote​:

On Sat, May 26, 2012 at 06​:10​:39PM -0700, James E Keenan via RT wrote​:

On Sat Sep 10 14​:08​:31 2005, schwern wrote​:

On Fri, Aug 26, 2005 at 09​:06​:50AM -0700, Steve Peters via RT wrote​:

$a = 10;
if (local $a = 1){
}
print $a; # Should be 10, not 1

Still busted in 5.8.6 and blead.

$ bleadperl -wle '$a = 10; if( local $a = 1 ) {} print $a'
Found = in conditional, should be == at -e line 1.
1
$ bleadperl -wle '$a = 10; if( my $a = 1 ) {} print $a'
Found = in conditional, should be == at -e line 1.
10

And still busted in 5.16.0.

The comparison to lexical vars is slightly misleading; its actually
lexical vars which are the more broken​: the scope of the visibility of the
'my' declaration doesn't match the scope of when the lexical is actually
freed​:

sub DESTROY \{ warn "DESTROY\(@&#8203;\_\)\\n" \}

\{
$x = 1;
if \(my $x = bless \[\]\) \{
    warn "in IF block&#8203;: $x\\n";
\}
warn "exited IF block&#8203;: $x\\n";
\}
warn "exited outer block&#8203;: $x\\n";

warn "\-\-\-\-\\n";

\{
$a = 1;

if \(local $a = 2\) \{
    warn "in IF block&#8203;: $a\\n";
\}
warn "exited IF block&#8203;: $a\\n";
\}
warn "exited outer block&#8203;: $a\\n";

which outputs​:

in IF block&#8203;: main=ARRAY\(0x235bde8\)
exited IF block&#8203;: 1
DESTROY\(main=ARRAY\(0x235bde8\)\)
exited outer block&#8203;: 1
\-\-\-\-
in IF block&#8203;: 2
exited IF block&#8203;: 2
exited outer block&#8203;: 1

Here, the scope of when the lexical is freed and when the 'local' is
undone, is consistently at the end of the enclosing block, which could
arguably be viewed as correct; however the visibility of the lexical
*declaration* is only for the inner block.

I've run into this several times in my own code, in the form of​:

  if (my $foo = something()) {
  # use $foo
  }
  elsif (my $foo = something_else()) {
  # use $foo
  }

which gives a '"my" variable $foo masks earlier declaration in same scope'
warning under "use warnings". It is somewhat irritating.

-doy

@toddr
Copy link
Member

toddr commented Aug 17, 2020

This ticket was erroneously migrated in a closed state

@toddr toddr reopened this Aug 17, 2020
@shadowcat-mst
Copy link
Contributor

I'm not convinced doy's thing is actually the same problem - the contents of the psuedoscope for the if condition should persist further on, given e.g.

sub foo { (1, 2) }
if (4 < (my @foo = foo())) { meh() } else { \@foo }

being perfectly reasonable code - the question of whether the elsif condition should regard itself as a direct continuation of the if condition's pseudoscope (in which case the warning is correct) or as a new pseudoscope deriving itself from the if condition's pseudoscope (in which case the code doy provides should be warning free) seems arguable either way but separate to the late-destroy problem AFAICT.

@Leont
Copy link
Contributor

Leont commented Jan 19, 2021

I believe the current behavior is the correct one in the bigger picture, even if I understand why the behavior proposed here is more intuitive at first

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

5 participants