This is an interesting edge case. I modified your code to eliminate $x, using localized $_ to see if that changed the behavior. It doesn't. Behold:
use strict; use warnings; my $cl3 = sub { local $_; foreach (0..1,5..6) { print $_++ , "\n"; } }; $cl3->(); $cl3->(); $cl3->();
This returns "015612672378". I ran it through B::Deparse to see what I wasn't seeing already. The deparsed version is like this:
use warnings; use strict 'refs'; my $cl3 = sub { local $_; foreach $_ ((0, 1), (5, 6)) { print $_++, "\n"; } } ; &$cl3(); &$cl3(); &$cl3();
If you run that, you get "Modification of a read-only value attempted at mytest.pl line 13." So deparse breaks your edge case by pre-enumerating the '..' lists.
Update: ikegami is probably right; you've found an optimization, and a way to demonstrate it changing a script's expected behavior. And given the fact that it's probably an optimization you've bumped into, it isn't surprising that the deparsed version isn't able to "benefit" from the optimization, since it enumerates out the .. list.
I'm curious: Every now and then someone posts one of these somewhat amazing but carefully constructed scenarios that exhibits an unexpected behavior or points out a bug. My curiosity is this, did you discover this while tracking down a real-world bug, while playing around with edge cases on your own, by reading the Perl source code, or was someone discussing it in some other forum (eg IRC or P5P) such that you caught wind of it and spilled it over into PerlMonks? I'm not making a value judgement, I always wonder how these things are first discovered. There have been a couple of oddities that I've uncovered while playing around with and refining obfuscations, for example.
Dave
In reply to Re: Unexpected behaviour with constant lists and foreach (and closures?)
by davido
in thread Unexpected behavior of '..' lists
by Crackers2
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |