Re: Logic for importing and strict vars?
by vr (Curate) on Feb 27, 2019 at 12:08 UTC
|
why the fourth of these examples is an error
I'd say it's in accordance with strict (emphasis mine):
strict vars
This generates a compile-time error if you access a variable that was neither explicitly declared (using any of my, our, state, or use vars ) nor fully qualified.
(Edit: to re-phrase, maybe it's more clear -- was neither explicitly declared nor is fully qualified.)
Thus, no surprise that next 2 lines fail:
perl -wMstrict -e "$::x=0; $x++" # not OK
perl -wMstrict -e "package foo; $foo::x=0; $x++" # not OK
Next 2 lines are your examples -- it's strange 2nd (your third) doesn't fail:
perl -wMstrict -e "BEGIN{*::x=\$a} $x++" # not OK (1)
perl -wMstrict -e "BEGIN{package foo; *::x=\$a} $x++" # OK (2)
It has something to do with BEGIN:
perl -wMstrict -e "{package foo; *::x=\$a} $x++" # not OK
the deparsed output is an insult:
C:\>perl -MO=Deparse -wMstrict -e "{package foo; *::x=\$a} $x++"
Variable "$x" is not imported at -e line 1.
Global symbol "$x" requires explicit package name (did you forget to d
+eclare "my
$x"?) at -e line 1.
-e had compilation errors.
BEGIN { $^W = 1; }
use strict;
{
package foo;
*main::x = \$a;
}
$main::x++;
But also with "main" package. Next 2 are symmetrical with examples (1) and (2), just with "bar" instead of "main", but both OK now:
perl -wMstrict -e "BEGIN{package bar; *bar::x=\$a} package bar; $x++"
+ # not OK
perl -wMstrict -e "BEGIN{package foo; *bar::x=\$a} package bar; $x++"
+ # OK
Edit 2: Actually, replacing "main" with "bar" doesn't change anything (fixed one of the lines above).
| [reply] [d/l] [select] |
|
It has something to do with BEGIN
I have found this information:
BEGIN: A BEGIN code block is executed as soon as possible, that is, the moment it is completely defined, even before the rest of the containing file (or string) is parsed
So I suspect that that means that in case the BEGIN is not there the parser will detect the variable $x before it is created. In case the BEGIN is there, it is guarantied to execute that block first, so before it sees $x (or in this case actually $main::x) and by that time it exists because the block has already been executed.
edit: It even looks like that BEGIN turns off certain warnings for this reason:
perl -MO=Deparse -wMstrict -e "{ package bla { *::x=\$a } }"
Name "main::x" used only once: possible typo at -e line 1.
...
perl -MO=Deparse -wMstrict -e "BEGIN { package bla { *::x=\$a } }"
# No problem
| [reply] [d/l] [select] |
|
It has something to do with BEGIN
In case the BEGIN is there, it is guarantied to execute that block first, so before it sees $x (or in this case actually $main::x) and by that time it exists because the block has already been executed.
Yes, I concur - and an interesting point regarding the warnings. I assume they don't occur because otherwise they'd get triggered by the import mechanism regularly, but it'd be interesting to find any docs on that, too...
| [reply] |
|
it's strange 2nd (your third) doesn't fail ... Actually, replacing "main" with "bar" doesn't change anything (fixed one of the lines above).
Yes, that's the logic that I was looking for "official" documentation on - the difference is, as tye said, "when the variable slot of a glob gets assigned to by code compiled into another package".
| [reply] |
Re: Logic for importing and strict vars?
by Eily (Monsignor) on Feb 27, 2019 at 08:31 UTC
|
To add a little strangeness; for your third proposition, on v5.10 Linux I get:
Name "blah::a" used only once: possible typo at -e line 1.
but I don't on v5.26 Windows :)
All I can say is that with B::Deparse the package prefix seems to be removed,
perl -MO=Deparse -wMstrict -e "BEGIN { *::x=\$a } $x++"
...
BEGIN { $^W = 1; }
use strict;
sub BEGIN {
*x = \$a;
}
$main::x++;
The output is exactly the same if I add package main; before setting *::x. (Also it replaces the $x++ by $main::x++, which would actually be valid code...) This might just be an optimization gone wrong? | [reply] [d/l] [select] |
|
Eily: All I can say is that with B::Deparse the package prefix seems to be removed,
No, that is turned around reasoning. I would say: The package prefix is not added.
The problem that is described here is not in the BEGIN block but the last $x++ statement which should be explicitly mentioned: $main::x++; because $x is not exported imported. The Parser translates to '$main::x' automatically because the package statement resides in the BEGIN block. When it is outside the BEGIN block, it doesn't do that. In none of the cases, the variable $x is exported imported.
edit: As far as documentation concerned I believe it can be found under: package, paragraph 2, the promise that a package statement does not affect lexically-scoped variables
| [reply] [d/l] [select] |
|
| [reply] |
|
on v5.10 Linux I get: Name "blah::a" used only once: possible typo at -e line 1. but I don't on v5.26 Windows :)
That'd be this change in v5.20: $a and $b warnings exemption
All I can say is that with B::Deparse the package prefix seems to be removed
True, although that's with the error still happening, I'm not sure if the deparse can be trusted in that case. It looks a little different without strict vars:
$ perl -MO=Deparse -wMstrict=refs,subs -e 'BEGIN { *::x=\$a } $x++'
BEGIN { $^W = 1; }
use strict 'refs', 'subs';
sub BEGIN {
*x = \$a;
}
++$x;
-e syntax OK
| [reply] [d/l] [select] |
Re: Logic for importing and strict vars?
by Eily (Monsignor) on Feb 27, 2019 at 13:18 UTC
|
Subs are special, perl doesn't care so much if a function is declared to allow it to be called, this is valid:
perl -cE "use strict; use warnings; myFunction()"
-e syntax OK
For the code to work you just need to have a function in the *::myFunction slot at execution time. So I guess this is why the second line works?
Now for the last one, tye's post actually has the answer:
when the variable slot of a glob gets assigned to by code compiled into another package
For the import to be valid, the glob as to be written from another package. | [reply] [d/l] |
|
$ perl -wMstrict -e 'BEGIN { *::x=sub{} } x'
$ perl -wMstrict -e 'BEGIN { *::x=sub{} } x()'
$ perl -wMstrict -e ' { *::x=sub{} } x()'
$ perl -wMstrict -e ' { *::x=sub{} } x'
Bareword "x" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.
$ perl -wMstrict -e 'x'
Bareword "x" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.
$ perl -wMstrict -e 'x()'
Undefined subroutine &main::x called at -e line 1.
$ perl -wMstrict -e '&x'
Undefined subroutine &main::x called at -e line 1.
| [reply] [d/l] |
Re: Logic for importing and strict vars?
by LanX (Saint) on Feb 27, 2019 at 13:19 UTC
|
I'm still sleepy and have no documentation...
Here my guess:
Strict doesn't complain about exported vars, they are "declared" implicitly.*
Your last line is not an export but only a simple aliasing, since $x and $a belong to the same package.
*) Most probably the same mechanism use vars is employing.
Update
The fact that $a is a special variable makes it even more complicated...
| [reply] [d/l] |
|
| [reply] [d/l] |
|
Maybe ...
You are talking about the exact mechanism that defines "exporting" resp. "Importing".
My statement holds the last line doesn't export.
Furthermore:
I can't see tye commenting here.
And using $a is unfortunate.
| [reply] |
|
|
|
$ perl -wMstrict -e 'BEGIN { package blah; *::x=\$::y } $x++'
Name "main::y" used only once: possible typo at -e line 1.
$ perl -wMstrict -e 'BEGIN { *::x=\$::y } $x++'
Variable "$x" is not imported at -e line 1.
Global symbol "$x" requires explicit package name (did you forget to d
+eclare "my $x"?) at -e line 1.
Execution of -e aborted due to compilation errors.
| [reply] [d/l] |
|
package Foo ;
use strict ;
our $t = 2 ;
{
BEGIN {
# package Bar ; # added
*Foo::x = \$Foo::t;
}
++$x ;
# ++$Foo::x; # no errors
print $x ;
# print $Foo::x; # no errors
}
Small note regards the Deparse results: With 'package Bar' disabled it looks like *Foo::x = \$Foo::t; becomes: *x = \$t; and with 'package Bar' enabled it becomes: *Foo::x = \$Foo::t;. Inside the BEGIN statement I think it is likely that the first form is not a valid trigger to 'declare' $x and the latter form is valid, but the reason could also be what tye said regards: "when the variable slot of a glob gets assigned to by code compiled into another package". But I am still confused though 'what' declared means. Is it turned into a lexical scoped package variable, or is it similar to 'use vars'?. This line in 'use' documentation is not clear to me:"...which are effective through the end of the file..." in the text: "Some of these pseudo-modules import semantics into the current block scope (like strict or integer , unlike ordinary modules, which import symbols into the current package (which are effective through the end of the file)".
In case you do wish to use this as a one-liner (Windows):
perl -MO=Deparse -wMstrict -e "package Foo ; our $t = 2 ; { BEGIN { package Bar { *Foo::x=\$Foo::t } } ; ++$x ; print $x }" | [reply] [d/l] [select] |
|
Re: Logic for importing and strict vars?
by LanX (Saint) on Feb 27, 2019 at 17:26 UTC
|
I don't think it is properly documented.
(You might find a mention in perlapi or perlguts but that's not my definition of proper.)
Probably the best place would be perlmod#Symbol-Tables which explains the *typeglob operator.
Plus cross-references coming in from strict, import ...
You could use perlbug to suggest patches to the docs.
HTH! :)
| [reply] |
|
| [reply] |
Re: Logic for importing and strict vars?
by Anonymous Monk on Feb 27, 2019 at 10:54 UTC
|
Why?
UTSL is the only real docs for implementation details. Everybody else just uses vars. | [reply] |
|
| [reply] |
|
Why would i look since im happy to use vars?
| [reply] |