in reply to Unexpected behavior of '..' lists

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

Replies are listed 'Best First'.
Re^2: Unexpected behaviour with constant lists and foreach (and closures?)
by Crackers2 (Parson) on Jul 20, 2006 at 19:11 UTC

    I ran into this one when I was doing some benchmarking. Specifically, I had something like this:

    cmpthese(10000, { 'orig' => sub { foreach my $x ( 0..9, 'a'..'v', 'A'..'V' ) { $x = M +yMod::MapChar($x); }}, 'new' => sub { foreach my $x ( 0..9, 'a'..'v', 'A'..'V' ) { $x = M +yMod::MapChar2($x); }}, } );

    I first wrote it without the $x =, but was thinking that this might trigger some void optimization, so I added that part (without thinking about the aliasing implications obviously). This made those subs bomb out with "invalid parameter" errors when they received "10".