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

[BUG our() 5.005_63] Lexical scoping problems. #1071

Closed
p5pRT opened this issue Jan 23, 2000 · 8 comments
Closed

[BUG our() 5.005_63] Lexical scoping problems. #1071

p5pRT opened this issue Jan 23, 2000 · 8 comments

Comments

@p5pRT
Copy link

@p5pRT p5pRT commented Jan 23, 2000

Migrated from rt.perl.org#2023 (status was 'resolved')

Searchable as RT2023$

@p5pRT
Copy link
Author

@p5pRT p5pRT commented Jan 23, 2000

From @schwern

our $a = "Outer";
{
  our $a = "Inner";
  print "$a\n";
}
print "$a\n";

$a is "Inner" in both places. If I understand how our() works, its
supposed to have the same scoping rules as my(). I would expect
"Inner" and then "Outer", same as my().

Next, our() doesn't appear to localize in a loop conditional​:

our $a = "Outer";
for (our $a = 1; $a < 2; $a++) {
  print "$a\n";
}
print "$a\n";

$a is 3, not "Outer" after the for loop. I presume the two bugs are
related.

However, this -does- work as expected.

our $a = "Outer";
for our $a (1, 2) {
  print "$a\n";
}
print "$a\n";

$a is 'Outer' after the for loop.

Summary of my perl5 (revision 5.0 version 5 subversion 63) configuration​:
  Platform​:
  osname=linux, osvers=2.2.10, archname=i686-linux
  uname='linux athens 2.2.10 #3 smp mon aug 2 16​:48​:09 edt 1999 i686 unknown '
  config_args=''
  hint=previous, useposix=true, d_sigaction=define
  usethreads=undef useperlio=undef d_sfio=undef
  use64bits=undef usemultiplicity=undef
  Compiler​:
  cc='cc', optimize='-g', gccversion=2.95.2 19991109 (Debian GNU/Linux)
  cppflags='-Dbool=char -DHAS_BOOL -DDEBUGGING -fno-strict-aliasing -I/usr/local/include -DDEBUGGING_OPS -DDEBUGGING_MSTATS'
  ccflags ='-Dbool=char -DHAS_BOOL -DDEBUGGING -fno-strict-aliasing -I/usr/local/include -DDEBUGGING_OPS -DDEBUGGING_MSTATS'
  stdchar='char', d_stdstdio=define, usevfork=false
  intsize=4, longsize=4, ptrsize=4, doublesize=8
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
  alignbytes=4, usemymalloc=y, prototype=define
  Linker and Libraries​:
  ld='cc', ldflags =' -L/usr/local/lib'
  libpth=/usr/local/lib /lib /usr/lib
  libs=-lnsl -lndbm -lgdbm -ldbm -ldb -ldl -lm -lc -lposix -lcrypt
  libc=/lib/libc-2.1.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'

Characteristics of this binary (from libperl)​:
  Compile-time options​: DEBUGGING
  Built under linux
  Compiled at Jan 3 2000 05​:17​:35
  @​INC​:
  /usr/local/perl5.005_63/lib/i686-linux
  /usr/local/perl5.005_63/lib
  /usr/local/perl5.005_63/lib/site_perl/i686-linux
  /usr/local/perl5.005_63/lib/site_perl
  .

--

Michael G Schwern schwern@​pobox.com
  http​://www.pobox.com/~schwern
  /(?​:(?​:(1)[.-]?)?\(?(\d{3})\)?[.-]?)?(\d{3})[.-]?(\d{4})(x\d+)?/i

@p5pRT
Copy link
Author

@p5pRT p5pRT commented Jan 23, 2000

From @gsar

On Mon, 24 Jan 2000 00​:01​:21 EST, Michael G Schwern wrote​:

I've bumped into a few basic scoping problems with our()​:

our $a = "Outer";
{
our $a = "Inner";
print "$a\n";
}
print "$a\n";

$a is "Inner" in both places.

Of course it is; both $a's are aliases to the same global. our doesn't
automatically local()ize. You need to explicitly spell that
C<local our $a = "Inner"> if that's what you want.

I think the "our" variable masks ... warning had better be extended
to warn on this case.

Sarathy
gsar@​ActiveState.com

@p5pRT
Copy link
Author

@p5pRT p5pRT commented Jan 23, 2000

From @schwern

On Sun, Jan 23, 2000 at 09​:38​:42PM -0800, Gurusamy Sarathy wrote​:

Of course it is; both $a's are aliases to the same global. our doesn't
automatically local()ize. You need to explicitly spell that
C<local our $a = "Inner"> if that's what you want.

Oh, then the docs in perlfunc are a little confusing. I read​:

  An our declares the listed variables to be valid
  globals within the enclosing block, file, or eval.
  That is, it has the same scoping rules as a "my"
  declaration, but does not create a local variable.

as basically, "it scopes just like a my() variable except you can
refer to it as a fully qualified variable"

Okay, so color me stupid, but why is our()'s lexical scoping
capabilities useful? Just for 'strict vars' reasons?

PS I just realized I've been using $a in my examples and tests, I
probably should be using something else.

--

Michael G Schwern schwern@​pobox.com
  http​://www.pobox.com/~schwern
  /(?​:(?​:(1)[.-]?)?\(?(\d{3})\)?[.-]?)?(\d{3})[.-]?(\d{4})(x\d+)?/i

@p5pRT
Copy link
Author

@p5pRT p5pRT commented Jan 24, 2000

From [Unknown Contact. See original ticket]

Michael G Schwern wrote​:

as basically, "it scopes just like a my() variable except you can
refer to it as a fully qualified variable"

Okay, so color me stupid, but why is our()'s lexical scoping
capabilities useful? Just for 'strict vars' reasons?

I can't see any situation where this is actually /necessary/, but as an
advocate of minimal scoping of variables, I have to approve :)

Consider a pair of functions that access the same data​:

  sub shove($) {
  our @​stack;
  push @​stack, shift;
  }

  sub prolapse() {
  our @​stack;
  pop @​stack
  }

A contrived example, of course, but until now this could only have been
achieved either with a global (that would be visible throughout the
module from its declaration) or a closure, which is fine unless your
code is running under mod_perl or a similar re-packaging mechanism...

Pete
--
use Disclaimer​::Standard;
my $phone='+44 1793 564450'; # "THIS IS THE COMPATIBILITY
my $fax='+44 1793 566918'; # POLICE. RESTORE YOUR ORIGINAL
my $mobile='+44 7973 725120'; # TOKE.C AND BACK AWAY SLOWLY."

@p5pRT
Copy link
Author

@p5pRT p5pRT commented Jan 24, 2000

From [Unknown Contact. See original ticket]

our() doesn't have any "local" component in it.

Consider​:

  # CASE 0​: grant access to global during scope,
  # but assign to it forever
  our $var = "fred";

is really like

  # CASE 1​: (same as previous)
  our $var;
  $var = "fred";

rather than like

  # CASE 2​: grant access to global during scope,
  # and also assign it a new, run-time value
  # for this block only
  our $var;
  local $var = "fred";

In other words, the duration of a run-time assignment in a
compiler-noted our() declaration on a global is itself permanent
in effect and wholly unconcerned with blocks, even though the
"use-strict-legal" visibility conferred by the our() modifier is
restricted to that lexical block.

You'd be wanting

  local our $var = "fred";

if you're expecting both. (And yes, it should be "our local" in
English.)

--tom

@p5pRT
Copy link
Author

@p5pRT p5pRT commented Jan 24, 2000

From [Unknown Contact. See original ticket]

          An our declares the listed variables to be valid
          globals within the enclosing block\, file\, or eval\.
          That is\, it has the same scoping rules as a "my"
          declaration\, but does not create a local variable\.

as basically, "it scopes just like a my() variable except you can
refer to it as a fully qualified variable"

Okay, so color me stupid, but why is our()'s lexical scoping
capabilities useful? Just for 'strict vars' reasons?

Because you're providing explicit access to a global variable.

  if ($x < 0) {
  our $count;
  $count++;
  }

  if ($x > 0) {
  print "got $count\n"; # ERROR; $count not seen
  }

If it this aspect of my() which our() mimics--it's restricting
access to the enclosing scope. You might also be wrongthinking
by expecting our() to nest. They don't. There's only ever one
our() variable. our() just says "ok to access global in this block".
If another block says the same thing, they're talking about the
same global variable.

my() is completely different. It can nest. You can have more than
one my() variable of the same name due to nesting, and these are
different variables, with different addresses, and with potentially
different values. If another block says the same thing, they're
*not* talking about the same variable, but two separate private
variables of the same name.

my() variables "belong" to private and unique lexical scopes, whereas
our() variables "belong" to packages, the home of global variables and
universally accessible.

  Perl => Meaning
  ----- -------
  my => local
  our => global
  local => save

--tom

@p5pRT
Copy link
Author

@p5pRT p5pRT commented Jan 24, 2000

From @TimToady

Pete Jordan writes​:
: Consider a pair of functions that access the same data​:
:
: sub shove($) {
: our @​stack;
: push @​stack, shift;
: }
:
: sub prolapse() {
: our @​stack;
: pop @​stack
: }

Or even​:

  sub shove($) { push our @​stack, shift }
  sub prolapse() { pop our @​stack }

Of course, that's not so different from

  sub shove($) { push @​MyPackage​::stack, shift }
  sub prolapse() { pop @​MyPackage​::stack }

but with C<our> you don't need to remember your own package name.

Larry

@p5pRT
Copy link
Author

@p5pRT p5pRT commented Jan 25, 2000

From @gsar

On Sun, 23 Jan 2000 21​:38​:42 PST, I wrote​:

On Mon, 24 Jan 2000 00​:01​:21 EST, Michael G Schwern wrote​:

I've bumped into a few basic scoping problems with our()​:

our $a = "Outer";
{
our $a = "Inner";
print "$a\n";
}
print "$a\n";

$a is "Inner" in both places.

Of course it is; both $a's are aliases to the same global. our doesn't
automatically local()ize. You need to explicitly spell that
C<local our $a = "Inner"> if that's what you want.

I think the "our" variable masks ... warning had better be extended
to warn on this case.

  % ./perl -Ilib -Mdiagnostics -we 'our $foo; { our $foo; }'
  "our" variable $foo redeclared at -e line 1 (#1)
 
  (W) You seem to have already declared the same global once before in the
  current lexical scope.
 
  (Did you mean "local" instead of "our"?) (#2)
 
  (W) Remember that "our" does not localize the declared global variable.
  You have declared it again in the same lexical scope, which seems superfluous.

Sarathy
gsar@​ActiveState.com

Inline Patch
-----------------------------------8<-----------------------------------
Change 4891 by gsar@auger on 2000/01/25 20:22:01

	produce redeclaration warning on C<our $foo; { our $foo; ... }>

Affected files ...

... //depot/perl/op.c#246 edit
... //depot/perl/pod/perldelta.pod#134 edit
... //depot/perl/pod/perldiag.pod#118 edit
... //depot/perl/t/pragma/strict-vars#9 edit

Differences ...

==== //depot/perl/op.c#246 (text) ====
Index: perl/op.c
--- perl/op.c.~1~	Tue Jan 25 12:29:52 2000
+++ perl/op.c	Tue Jan 25 12:29:52 2000
@@ -153,22 +153,39 @@
     }
     if (ckWARN(WARN_UNSAFE) && AvFILLp(PL_comppad_name) >= 0) {
 	SV **svp = AvARRAY(PL_comppad_name);
-	for (off = AvFILLp(PL_comppad_name); off > PL_comppad_name_floor; off--) {
+	HV *ourstash = (PL_curstash ? PL_curstash : PL_defstash);
+	PADOFFSET top = AvFILLp(PL_comppad_name);
+	for (off = top; off > PL_comppad_name_floor; off--) {
 	    if ((sv = svp[off])
 		&& sv != &PL_sv_undef
 		&& (SvIVX(sv) == PAD_MAX || SvIVX(sv) == 0)
+		&& (PL_in_my != KEY_our
+		    || ((SvFLAGS(sv) & SVpad_OUR) && GvSTASH(sv) == ourstash))
 		&& strEQ(name, SvPVX(sv)))
 	    {
-		if (PL_in_my != KEY_our
-		    || GvSTASH(sv) == (PL_curstash ? PL_curstash : PL_defstash))
+		Perl_warner(aTHX_ WARN_UNSAFE,
+		    "\"%s\" variable %s masks earlier declaration in same %s", 
+		    (PL_in_my == KEY_our ? "our" : "my"),
+		    name,
+		    (SvIVX(sv) == PAD_MAX ? "scope" : "statement"));
+		--off;
+		break;
+	    }
+	}
+	if (PL_in_my == KEY_our) {
+	    while (off >= 0 && off <= top) {
+		if ((sv = svp[off])
+		    && sv != &PL_sv_undef
+		    && ((SvFLAGS(sv) & SVpad_OUR) && GvSTASH(sv) == ourstash)
+		    && strEQ(name, SvPVX(sv)))
 		{
 		    Perl_warner(aTHX_ WARN_UNSAFE,
-			"\"%s\" variable %s masks earlier declaration in same %s", 
-			(PL_in_my == KEY_our ? "our" : "my"),
-			name,
-			(SvIVX(sv) == PAD_MAX ? "scope" : "statement"));
+			"\"our\" variable %s redeclared", name);
+		    Perl_warner(aTHX_ WARN_UNSAFE,
+			"(Did you mean \"local\" instead of \"our\"?)\n");
+		    break;
 		}
-		break;
+		--off;
 	    }
 	}
     }

==== //depot/perl/pod/perldelta.pod#134 (text) ====
Index: perl/pod/perldelta.pod
--- perl/pod/perldelta.pod.~1~	Tue Jan 25 12:29:52 2000
+++ perl/pod/perldelta.pod	Tue Jan 25 12:29:52 2000
@@ -1549,11 +1549,6 @@
 
 =over 4
 
-=item "my sub" not yet implemented
-
-(F) Lexically scoped subroutines are not yet implemented.  Don't try that
-yet.
-
 =item "%s" variable %s masks earlier declaration in same %s
 
 (W) A "my" or "our" variable has been redeclared in the current scope or statement,
@@ -1562,6 +1557,16 @@
 until the end of the scope or until all closure referents to it are
 destroyed.
 
+=item "my sub" not yet implemented
+
+(F) Lexically scoped subroutines are not yet implemented.  Don't try that
+yet.
+
+=item "our" variable %s redeclared
+
+(W) You seem to have already declared the same global once before in the
+current lexical scope.
+
 =item '!' allowed only after types %s
 
 (F) The '!' is allowed in pack() and unpack() only after certain types.
@@ -1802,6 +1807,11 @@
 
 See Server error.
 
+=item Did you mean "local" instead of "our"?
+
+(W) Remember that "our" does not localize the declared global variable.
+You have declared it again in the same lexical scope, which seems superfluous.
+
 =item Document contains no data
 
 See Server error.

==== //depot/perl/pod/perldiag.pod#118 (text) ====
Index: perl/pod/perldiag.pod
--- perl/pod/perldiag.pod.~1~	Tue Jan 25 12:29:52 2000
+++ perl/pod/perldiag.pod	Tue Jan 25 12:29:52 2000
@@ -31,6 +31,14 @@
 
 =over 4
 
+=item "%s" variable %s masks earlier declaration in same %s
+
+(W) A "my" or "our" variable has been redeclared in the current scope or statement,
+effectively eliminating all access to the previous instance.  This is almost
+always a typographical error.  Note that the earlier variable will still exist
+until the end of the scope or until all closure referents to it are
+destroyed.
+
 =item "my sub" not yet implemented
 
 (F) Lexically scoped subroutines are not yet implemented.  Don't try that
@@ -42,19 +50,16 @@
 to try to declare one with a package qualifier on the front.  Use local()
 if you want to localize a package variable.
 
-=item "%s" variable %s masks earlier declaration in same %s
-
-(W) A "my" or "our" variable has been redeclared in the current scope or statement,
-effectively eliminating all access to the previous instance.  This is almost
-always a typographical error.  Note that the earlier variable will still exist
-until the end of the scope or until all closure referents to it are
-destroyed.
-
 =item "no" not allowed in expression
 
 (F) The "no" keyword is recognized and executed at compile time, and returns
 no useful value.  See L<perlmod>.
 
+=item "our" variable %s redeclared
+
+(W) You seem to have already declared the same global once before in the
+current lexical scope.
+
 =item "use" not allowed in expression
 
 (F) The "use" keyword is recognized and executed at compile time, and returns
@@ -1284,6 +1289,11 @@
 
 (W) You probably referred to an imported subroutine &FOO as $FOO or some such.
 
+=item Did you mean "local" instead of "our"?
+
+(W) Remember that "our" does not localize the declared global variable.
+You have declared it again in the same lexical scope, which seems superfluous.
+
 =item Did you mean $ or @ instead of %?
 
 (W) You probably said %hash{$key} when you meant $hash{$key} or @hash{@keys}.

==== //depot/perl/t/pragma/strict-vars#9 (text) ====
Index: perl/t/pragma/strict-vars
--- perl/t/pragma/strict-vars.~1~	Tue Jan 25 12:29:52 2000
+++ perl/t/pragma/strict-vars	Tue Jan 25 12:29:52 2000
@@ -339,3 +339,18 @@
 our $foo;
 EXPECT
 "our" variable $foo masks earlier declaration in same scope at - line 7.
+########
+
+# multiple our declarations in same scope, same package, warning
+use strict 'vars';
+use warnings;
+our $foo;
+{
+    our $foo;
+    package Foo;
+    our $foo;
+}
+EXPECT
+"our" variable $foo redeclared at - line 7.
+(Did you mean "local" instead of "our"?)
+Name "Foo::foo" used only once: possible typo at - line 9.
End of Patch.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
1 participant