Re: Missing error under strict
by LanX (Saint) on Jul 23, 2019 at 02:19 UTC
|
> Why am I not getting an error message for line 10?
my is declaring $one for the rest of the scope.
say 'one' until my $one = 1;
Scope is the file because post-fix constructs have no surrounding block.
> Global symbol "$two" requires explicit package name at ./strict.pl line 16.
The scope here is limited to the loop and won't reach the say
until (my $two = 2) {
say 'two';
}
say $two;
> Commenting out line 16 gives me:
Then you have no compile time fatals from strict anymore and the script runs
> Use of uninitialized value $one in say at ./strict.pl line 10.
that's a run-time warning ...
... I'm a bit puzzled and need to run the code, to see why my $one is not initialized
update
The condition after until should be executed at least once.
I can only guess that some kind of weird optimization is happening there.
Please note that using my in conditional code is considered bad practice and might not be well tested.
You might have found a bug here.
update
My guess is that scope handling is wrong here.
At runtime a variable should be reset to undef at the end of it's loop-scope.
Of course this is in conflict with Perl's compile-time behavior of not seeing a scope here.
| [reply] [d/l] [select] |
Re: Missing error under strict
by swl (Prior) on Jul 23, 2019 at 02:07 UTC
|
| [reply] |
|
| [reply] |
Re: Missing error under strict (Perlbug: postfix 'until' has inconsistent scope)
by LanX (Saint) on Jul 23, 2019 at 11:28 UTC
|
I boiled the problem down to this code
warn $]; #> 5.024001
$null = 1;
warn 'never' until $null = 666;
warn $null; #> 666
$one = 1;
warn 'never' until my $one = 666; # my !
warn $one; #> Warning: something's wrong
+at ...
B::Deparse didn't show anything suspicious
D:\tmp>perl -MO=Deparse tst_scope.pl
warn $];
$null = 1;
warn 'never' until $null = 666;
warn $null;
$one = 1;
warn 'never' until my $one = 666;
warn $one;
tst_scope.pl syntax OK
I also looked at B::Concise , but couldn't spot a difference in op-code flow.
My guess is still that until has an inconsistency in scope between compile-time and run-time and is erroneously resetting the lexical variable.
update
PS: I have problem to imagine practical code, where this bug is posing a problem. | [reply] [d/l] [select] |
|
It's a bug definitely. When using if instead of until, it outputs 666.
> I have problem to imagine practical code, where this bug is posing a problem.
The bug might manifest in other places, too, where it can cause serious headaches. I've already reported a bug for this Perl version, do you want to have your name mentioned in the Thanks section?
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] [select] |
|
> . I've already reported a bug for this Perl version, do you want to have your name mentioned in the Thanks section?
sure and a link to the thread here please
something like
Thanks to Lanx who is normally to busy/lazy to report perlbugs
;-)
> The bug might manifest in other places, too, where it can cause serious headaches.
Sure that's why I've put so much effort into it. But I think the chances are <1%.
| [reply] |
|
|
|
use strict;
use warnings;
use feature qw'say state';
{no strict; no warnings;
$three = 1;
say 'three' until $three++ == 3;
}
#Use of uninitialized value $two in say at SoPW_11103184.pm line 54
say 'two' until my $two = 2;
#say 'owt',$two;
say 'one' until state $one = 1;
say 'eno',$one;
{no strict; no warnings;
say $zero until $zero = 9;
}
say our $minone = 5 until $minone = 8;
say $minone;
# says '5' continuously
#say our $mintwo = 5 until 3 == $mintwo--;
#say $mintwo;
__END__
three
three
#say $two #uninit warning
eno1
8
Depending how the scope is declared determines if the assignment is fully evaluated
Can't find method 'say' in Module 'Died at ....' at ... | [reply] [d/l] |
|
| [reply] [d/l] |
|
|
|
> I boiled the problem down to this code
Here you are initializing a seperate variable before the until, which is getting reset by the my inside the until. In my code I was initializing the variable inside the until, and then attempting to use it after. Seems like two different (but related) bugs to me.
> PS: I have problem to imagine practical code, where this bug is posing a problem.
My original code:
$count++ until my %boxes = fit($count, $quota, @sizes);
I wasn't sure about the scope when I wrote that line, but figured worst case I would get a compile error and move the my to the line above. Had a hell of a time figuring out why %boxes was always null when I tried to access it later (it should loop until %boxes is not null). | [reply] [d/l] |
|
My intention was to proof a bug in short code.
There is no possible explanation for an undefined value after the loop. Hence a bug.
> Here you are initializing a seperate variable before the until, which is getting reset by the my inside the until.
This statement doesn't really make sense, if the variables are different they can't reset each other.
As already explained does my have a compile time and a runtime effect, which are inconsistent in this case.
> Seems like two different (but related) bugs to me.
No. Everything else was explained.
> My original code:
> $count++ until my %boxes = fit($count, $quota, @sizes);
Thanks, nice example.
FWIW a workaround is to put the my declaration right before the loop.
| [reply] [d/l] [select] |
Re: Missing error under strict
by Don Coyote (Hermit) on Jul 23, 2019 at 13:07 UTC
|
Hello Pascal666
The until BLOCK enters a new lexical scope. When used in BLOCK form. When used as a statement modifier the scope has not entered into a BLOCK. The lexical scope is at the file level so there is no need for strict to complain.
I was going to suggest using the feature state but this does not change the problem. It does however allow scoping to take place within the block
Variables lexically scoped with my will be initialised, then get undefined when leaving the scope. As the scope is the body of a loop this re-occurs each iteration
Variables lexically scoped with state will be initialsed but with enough mana to last till the scope exits at the completion of the loop, whence they will meet their timely fate.
Change the state and my declarations in the following code, but if you use both my, make sure to uncomment the last three lines of the loop.
use strict;
use warnings;
use feature qw'say state';
until ( (state $two = 2)[0] == 2*2*2 ) {
state $four = 16;
last unless $four;
say --$four =~ /\d{2}/ ? "$four" : '0'.$four, ': ',$two++ ;
# my my ? uncomment
# state $FOUR=64;
# $FOUR >= 48 and print '$FOUR: ',$FOUR;
# last unless $FOUR--;
}
say 'owt: ',my $two=2;
Edited main scope to say file scope, re LanX | [reply] [d/l] |
|
> The lexical scope is still main so there is no need for strict to complain.
what do you mean with lexical scope "main"?
If you mean the package main:: , there is nothing like a lexical scope there, packages are global.
In this case it's the file scope.
| [reply] |