Open p5pRT opened 8 years ago
The following program:
my $i; sub announce { printf "Count %d\n"\, $i }
for $i (1..3) { announce(); }
It emits
Count 0 Count 0 Count 0
But it should be
Count 1 Count 2 Count 3
Also\, when correcting that bug\, please make sure this is also corrected:
for my $i (1..3) { sub announce { printf "Count %d\n"\, $i } announce(); }
It shows the same wrong behavior.
On Wed Sep 28 17:50:35 2016\, mjd@plover.com wrote:
This is a bug report for perl from mjd@plover.com\, generated with the help of perlbug 1.39 running under perl 5.18.2.
----------------------------------------------------------------- [Please describe your issue here]
The following program:
my $i; sub announce { printf "Count %d\n"\, $i }
for $i (1..3) { announce(); }
It emits
Count 0 Count 0 Count 0
But it should be
Count 1 Count 2 Count 3
Also\, when correcting that bug\, please make sure this is also corrected:
for my $i (1..3) { sub announce { printf "Count %d\n"\, $i } announce(); }
It shows the same wrong behavior.
Why\, in a similar circumstance\, does 'print' behave differently from 'printf'?
##### $ cat 129757-other.pl my $j; sub denounce { print "Count $j\n"; }
for $j (1..3) { denounce(); }
$ perl 129757-other.pl Count Count Count #####
Thank you very much. -- James E Keenan (jkeenan@cpan.org)
The RT System itself - Status changed from 'new' to 'open'
On Thu\, Sep 29\, 2016 at 3:05 AM\, James E Keenan via RT \< perlbug-followup@perl.org> wrote:
Why\, in a similar circumstance\, does 'print' behave differently from 'printf'?
It's not different\, is it?
Well\, okay\, %d in the pattern to printf evaluates it in numeric context (getting 0)\, while double-quote interpolation evaluates it in string context (getting '')\, but in either case\, the variable is undefined (as you would see if running the snippets with warnings enabled).
Eirik
* James E Keenan via RT \perlbug\-followup@​perl\.org [2016-09-28T21:05:02]
Why\, in a similar circumstance\, does 'print' behave differently from 'printf'?
~$ perl -e 'my $x = undef; printf "%d\n"\, $x' 0 ~$ perl -e 'my $x = undef; print "$x\n"'
The %d format numifies undef.
~$ perl -Mwarnings -e 'my $x = undef; printf "%d\n"\, $x' Use of uninitialized value $x in printf at -e line 1. 0 ~$ perl -Mwarnings -e 'my $x = undef; print "$x\n"' Use of uninitialized value $x in concatenation (.) or string at -e line 1.
-- rjbs
# A self-contained test that shows the correct behavior and doesn't get into print/printf.
require "t/test.pl";
my $i = 2112;
ok( $i == 2112\, '$i starts at 2112' );
my $n; for $i (1..3) { ++$n; ok( $i == $n\, '$i is ' . $n . ' inside of the for loop' ); somesub(); }
ok( $i == 2112\, '$i should go back to 2112 outside of the loop' );
exit 0;
sub somesub { ok( $i == $n\, '$i is ' . $n . ' in the subroutine' ); }
* Mark-Jason Dominus \perlbug\-followup@​perl\.org [2016-09-29 03:00]:
The following program:
my $i; sub announce { printf "Count %d\n"\, $i }
for $i (1..3) { announce(); }
It emits
Count 0 Count 0 Count 0
But it should be
Count 1 Count 2 Count 3
Maybe. But that might affect this:
$ perl -E 'my @i; for my $i (5..8) { push @i\, sub { say $i } }; $_->() for @i' 5 6 7 8
That behaviour must not break under any circumstances.
To make that work\, in each iteration\, foreach rebinds the name $i to the scalar for that iteration:
perl -E 'my @i = (5..8); for my $i (@i) { say \$i eq \$i[$a++] }' 1 1 1 1
It seems to me that this binding is necessarily lexical to the loop block scope.
Meanwhile the `announce` sub has already closed over $i at compile time.
I donât know that itâs possible to change either of these facts. Not to mention doing it in such a way that closing over the loop variable at runtime would remain unaffected.
The straightforward way to get your âcorrectâ output would be to change foreach to do local()-style value shadowing with the same scalar. Which would break a huge amount of code\, and I think it would generally be a worse default\, even though one consequence of the current behaviour is the case you ran into here.
You can always use while() when you need it.
Also\, when correcting that bug\, please make sure this is also corrected:
for my $i (1..3) { sub announce { printf "Count %d\n"\, $i } announce(); }
It shows the same wrong behavior.
That sub is compiled just once despite its placement inside the loop and it binds $i at compile time.
Arguably perl ought to warn about this\, the same way that it warns when you make the same mistake but you write it this way:
sub do_announce { my $i = shift; sub announce { printf "Count %d\n"\, $i } announce(); }
That throws the infamous âwill not stay sharedâ warning. But you would not want this to start warning:
{ my $count = 0; sub announce { printf "Count %d\n"\, $count } }
I donât know how hard it would be to distinguish sure-fire warn-worthy situations from benign ones here.
Regards\, -- Aristotle Pagaltzis // \<http://plasmasturm.org/>
On Wed Sep 28 21:01:34 2016\, aristotle wrote:
* Mark-Jason Dominus \perlbug\-followup@​perl\.org [2016-09-29 03:00]:
Also\, when correcting that bug\, please make sure this is also corrected:
for my $i (1..3) { sub announce { printf "Count %d\n"\, $i } announce(); }
It shows the same wrong behavior.
That sub is compiled just once despite its placement inside the loop and it binds $i at compile time.
This is similar to the problem that plagues lexical aliasing. The notes I added in 514e62e37b8 may also be relevant to package subs\, but I do not have time to think it through now\, or in the foreseeable future.
--
Father Chrysostomos
Migrated from rt.perl.org#129757 (status was 'open')
Searchable as RT129757$