in reply to static-like persistence of my variable due to trailing conditional

My guess as to what is happening here is when you call mycode() the second time with no parameters, the my $foo = "blah" is not executed because the if $var condition.

Therefore, the $foo referenced in the $foo ||= "FOO"; line is a MAIN::$foo not a local one. Hence the output from the third and fourth calls.

Update: In the light of hossman's post I guess I guessed wrong!

I must stop guessing; I must stop guessing

Replies are listed 'Best First'.
Re: Re: static-like persistence of my variable due to trailing conditional
by hossman (Prior) on Jun 29, 2002 at 21:49 UTC
    The problem is definitely that the whole line "my $foo = "blah" if $var;" isn't getting executed (including the my $foo declaration) ... you can see the expected behavior if you change it to : "my $foo; $foo = "blah" if $var;"

    But a global $foo isn't getting set -- otherwise "-w/use strict" would complain.

    I honestly have no idea what in the semantic rules of Perl describes the behavior you are seeing. Why this compiles, and does what it does without complianing is beyond me. I would expect it to complain the same way this does...

    #!/usr/bin/perl -w use strict; sub mycode { my $var = $_[0]; my $foo = "blah" if $var; print "foo is $foo\n" if $foo; $bar ||= "BAR"; } mycode("test"); mycode(); mycode(); mycode();
      It looks like you are absolutely right. The output of perl -MO=Deparse,-p a.pl follows (after removing Data::Dumper):

      sub mycode { (my $var = $_[0]); (defined($var) ? print("mycode() called with $var\n") : print("mycode() called with no operands.\n")); ($var and (my $foo = 'blah')); #^^^^^^^^^^^^^^^ Look here ($foo and print("foo is $foo\n")); ($foo ||= 'FOO'); } mycode('test'); mycode(); mycode(); mycode(); a.pl syntax OK

      my $foo = 'blah' is optimized away.

      In order to make it behave as expected, my $foo; needs to be its own statement, with no conditional.

      Update: Removed bit about strict, see the follow up

        my $foo = 'blah' is optimized away. It looks like $foo is still in the symbol table for mycode, so strict doesn't complain on any subsequent calls.
        Hmm. I don't agree and/or don't completely understand what you're saying. (1) What do you mean by "optimized away"? (2) if $foo is in a symbol table, can you provide example code to print foo outside of the sub mycode{} block?

        On a side note, does anyone know of links/books/perldoc that I can look at which document this "feature"?

        ---
        "A Jedi uses the Force for knowledge and defense, never for attack."
Re: Re: static-like persistence of my variable due to trailing conditional
by DamnDirtyApe (Curate) on Jun 29, 2002 at 21:52 UTC

    I'm not sure that quite works. In theory, on the first call, my $foo = "blah" should be run, then go out of scope at the end of the function call. So, if the declaration/assignment is not run on the second call, shouldn't $foo ||= "FOO" give us an error?


    _______________
    D a m n D i r t y A p e
    Home Node | Email
      I vaguely recall reading something about the duality of run-/compilation timeness of my causing this. Unless I'm off by several orbits, the cause was that the scope is determined at compilation time, but the actual scalar is allocated at runtime, and is the same thing as causes $bar to persist in things like
      sub foo { my $bar = 0; sub baz { print $bar++; } }
      (You know the drill - Variable "$bar" will not stay shared.)

      Makeshifts last the longest.

      The reason we cant give an error is because my $foo = "blah" only gets executed if $var is true. However, we dont actually know if $var is true or not until runtime.

      So when you call mycode() with no arguments then my $foo = 'blah' is not executed at all. Instead, simply $foo = 'FOO' gets executed, setting $main::foo (you can verify this by printing out $main::foo after you call mycode() with no arguments).

      use strict is only supposed to catch compile-time errors (according to its documentation). It should not blow up at runtime.

      To do what you expect here you could do something like:

      
          my $foo = defined $var ? 'blah' : 'FOO';
      or even:
      
          my $foo;
          if ($var) {
              $foo = 'blah';
          }
          else {
              $foo = 'FOO';
          }
      
        my $foo = 'blah' is not executed at all. Instead, simply $foo = 'FOO' gets executed, setting $main::foo (you can verify this by printing out $main::foo after you call mycode() with no arguments).

        Wrong. Actually, the fact that $foo is scoped lexically must be known at compile time - think about it, how else would strict work? After the compiler sees a my, it generates ops referring to lexicals rather than globals for the variables. However, allocation of these lexicals happens at runtime. By adding an if, you prevent the allocation at runtime, but you do not prevent the lexical scoping that happens at compile time.

        The effect is that subsequent invocations of the routine refer to a lexically scoped scalar that was allocated in a previous invocation - the same way as closures do.

        Makeshifts last the longest.

        I concur, except for this part:
        So when you call mycode() with no arguments then my $foo = 'blah' is not executed at all. Instead, simply $foo = 'FOO' gets executed, setting $main::foo (you can verify this by printing out $main::foo after you call mycode() with no arguments).
        I had a line in my original code that dumped the symbol table:

        print Dumper(\%main::);

        But threw this out because I am never able to see $foo in the symbol table for the main package. Are you?

        ---
        "A Jedi uses the Force for knowledge and defense, never for attack."