saintmike has asked for the wisdom of the Perl Monks concerning the following question:

Quick pop quiz:

What's going to happen if you run the following:

use strict; my $rv = 42 for (1); print "$rv\n";
Possible Answers:

(a) strict will complain because my $rv is technically enclosed in a for block, rendering $rv in the print statement a global.

(b) $rv will be set to 42 after the for loop, so the print statement will print 42.

(c) Neither (a) nor (b).

Who gets it?

Replies are listed 'Best First'.
Re: my Scope Pop Quiz
by ysth (Canon) on Apr 08, 2005 at 20:12 UTC
    The behaviour here is officially undefined. perlsyn:
    NOTE: The behaviour of a my statement modified with a statement modifier conditional or loop construct (e.g. my $x if ...) is undefined. The value of the my variable may be undef, any previously assigned value, or possibly anything else. Don't rely on it. Future versions of perl might do something different from the version of perl you try it out on. Here be dragons.
Re: my Scope Pop Quiz
by ikegami (Patriarch) on Apr 08, 2005 at 20:10 UTC

    This came up recently, so I know that:

    1) strict doesn't complain. $rv is in a foreach loop, but it's not in a block (so it's file scoped).

    2) I have no idea why, but after the loop, $rv will be set to the null string ("") and not 42 or undef. Therefore, the output will be a blank line.

    my ... foreach ... is to be avoided.

    Update: While I don't get any warnings under -w or use warnings, print(defined($rv)?1:0, "\n"); prints 0, indicating $rv is undefined. ActivePerl v5.6.1

      $rv is clearly undefined. An undefined value is represented by an empty string when printed (whether it is in an interpolated string or not).

      #!/usr/bin/perl use strict; my $rv = 42 for (1); print "rv unquoted: '", $rv, "'\n"; print "rv quoted: '$rv'\n";
        An undefined value is represented by an empty string when printed

        yes, but an undefined value should also print a warning under -w when one attempts to print it, and I'm not getting any warnings when I specify -w. Very odd.

      >perl -v This is perl, v5.8.3 built for i386-linux-thread-multi Copyright 1987-2003, Larry Wall Perl may be copied only under the terms of either the Artistic License + or the GNU General Public License, which may be found in the Perl 5 source ki +t. Complete documentation for Perl, including FAQ lists, should be found +on this system using `man perl' or `perldoc perl'. If you have access to + the Internet, point your browser at http://www.perl.com/, the Perl Home Pa +ge. >cat rv #!/usr/bin/perl -w use strict; my $rv = 42 for (1); print "$rv\n"; >./rv Use of uninitialized value in concatenation (.) or string at ./rv line + 4. >perl -Mstrict -wle'my $rv=42 for (1); print ">$rv<"' Use of uninitialized value in concatenation (.) or string at -e line 1 +. >< >

      Cheers,
      R.

      Pereant, qui ante nos nostra dixerunt!
Re: my Scope Pop Quiz
by ww (Archbishop) on Apr 08, 2005 at 20:21 UTC
    (c.)
    But, contrary to what I would have expected from ike's above, dumping $rv from
    perl -d strictscript.pl
    tells me that $rv remains undef right up to exit.
    Clarification anyone? ysth cites the doc, but that leaves me unclear what the conditions/criteria are that trigger the variant behaviours. Or must we simply accept that undefined behavior cannot ever be predicted?

    Update: ikegami and I are both testing against AS on 'doze, but I'm using 5.8.6 build 811 here on (bastardized) w2k.

    However, re dave_the_m's below, don't recall (and too lazy to hunt up now) anything in the delta docs that suggested any change in scoping that was obviously relevant here.

    dave_the-m's observation "that might change" (understood as: "future vers may not behave the same way") summarizes my previous understanding of "undefined behavior" but the diff between ike's results and mine, on systems with no-known-relevant delta suggests something more akin to "random behaviour."

      Or must we simply accept that undefined behavior cannot ever be predicted
      That's the whole point of undefined behaviour :-)

      As it happens there's a difference between the compile-time and run-time scope of $rv; at compile time its scoped to EOF so the print sees the same lexical; at run-time its scoped to the loop, so gets set to undef at the end of the loop. But that might change.

      Stuff where the loop may not get executed, such as my $rv if $false gets more complicated.

      Dave.

      There hasn't been a change in scoping between perl versions (AFAIKT); it's always been like that, and it ends up undef on every perl I've tested it on from 5.5003 to 5.9.2. So the behaviour appears to be predictable, but you should't rely on it. For example, saying 'its undefined behaviour' reserves us the right to change its behaviour to something totally random if that makes the internal implementation more efficient.

      Dave.

Re: my Scope Pop Quiz
by kscaldef (Pilgrim) on Apr 09, 2005 at 06:12 UTC

    Hi Mike... I see you beat me to posting this :-)

    I assert that this should be considered a bug in strict, considering both the documentation that the behavior is undefined, and that B::Deparse says:

    % perl -MO=Deparse -Mstrict -le 'my $rv = 42 for (1); print $rv' + BEGIN { $/ = "\n"; $\ = "\n"; } use strict 'refs'; foreach $_ (1) { my $rv = 42; } print $rv; -e syntax OK

    but

    % perl -MO=Deparse -Mstrict -le 'foreach (1) { my $rv = 42 } ; print $ +rv' Global symbol "$rv" requires explicit package name at -e line 1. -e had compilation errors. BEGIN { $/ = "\n"; $\ = "\n"; } use strict 'refs'; foreach $_ (1) { my $rv = 42; } print ${'rv'};