Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

A curious case of of my()

by fleetingflicker (Initiate)
on Apr 05, 2011 at 08:32 UTC ( #897458=perlquestion: print w/ replies, xml ) Need Help??
fleetingflicker has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I have a curious case of using "my" in a sub that I couldn't quite think it through.
I am just wondering if anyone can lend me some perl wisdom on this.

sub foo{ my $var = shift; my $href = shift; my @array = $href->{pass_in} if defined $href and exists $href->{pass_ +in}; push @array, $var; print "contents : @array"; } foo(1); foo(2);
output : contents : 1 contents : 1 2

So my question is that why @array is behaving like a static variable in C language here?

Comment on A curious case of of my()
Select or Download Code
Re: A curious case of of my()
by Anonymous Monk on Apr 05, 2011 at 08:38 UTC
Re: A curious case of of my()
by moritz (Cardinal) on Apr 05, 2011 at 09:23 UTC
    Quoting 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.

    (emphasis partially mine)

Re: A curious case of of my()
by JavaFan (Canon) on Apr 05, 2011 at 09:40 UTC
    So my question is that why @array is behaving like a static variable in C language here?
    It's an artifact of the implementation (and in particular, with an optimization). my has compile-time and run-time effects, and due to the if statement, not all run-time effects happen. As pointed out before, don't rely on it - it may not work like this in the future. And it may not work as expected now either - it won't act like a static C variable if you use recursion:
    #!/usr/bin/perl use 5.010; use strict; use warnings; sub foo { my $x if 0; say ++$x; } sub bar { my $x if 0; say ++$x; bar() if @_; } foo; foo; bar(1); __END__ Deprecated use of my() in false conditional at ./x line 10. Deprecated use of my() in false conditional at ./x line 15. 1 2 1 1
    Note that the second time bar() is called (due to recursion), you do get a different $x - unlike the foo() case.

    Since 5.10, there is a warning on my $foo if 0; (at compile time). People have argued there should always be a warning on any my $foo if EXPR or my $foo = EXPR1 if EXPR2; usage, but that hasn't happened, and isn't happening in blead either.

    Also since 5.10, if you want a static variable, you can use the state keyword.

      Thanks JavaFan and LanX.
      Points on compile-time and run-time difference are well taken.
      BTW, in my original code, I do use strict/warning, and knew that separating the declaration and condition statement makes it work as expected. But still knowing a little more about what is going on under the hood is more satisfactory.
Re: A curious case of of my()
by SimonClinch (Chaplain) on Apr 05, 2011 at 09:45 UTC
    The answer is that @array is global variable - not a C-style local static one. The declaration with my is never executed because the "if" test fails.

    Separate the my declaration from the conditional assignment and suddenly "my" is applied as "expected"

    try also using the strict and warnings pragmas in your coding.

    One world, one people

      The answer is that @array is global variable
      Bullshit.

      @array is a lexical variable.

      The declaration with my is never executed because the "if" test fails.
      Bullshit.

      The declaration part of my is being done. Because that happens at compile time.

      Try also using the strict and warnings pragmas in your coding.
      The code presented is strict clean, and warnings free. Don't go pretending strict and warnings are silver bullets. They aren't.
        >The code presented is strict clean, and warnings free. Don't go pretending strict and warnings are silver bullets. They aren't.

        But garlic and cheaper than bullets!

        use strict; use warnings; sub tst { my $y if 0; # throws "Deprecated use of my() in false c +onditional" => 123 # my $y if shift; # no warning + => 112 print ++$y } tst(1); tst(); tst();

        Anything that helps should be used...

        Cheers Rolf

        I did of course test my assertions before presenting them. Separating the "my" from the if makes the problem go away. If the array were lexically declared it would not persist between calls to the subroutine. What do you think is happening - C static declaration leaked in there? Hardly! All of your points are in fact incorrect. In addition your style of argument is unacceptable to more educated people. Perhaps if you were more careful in your analysis to improve your accuracy, you wouldn't need to use expletives and straw men (like creating a line of argument, implying dishojnestly that another said it and then shooting it down) to sell your fallacies. I don't like dishonest people - go away.

        One world, one people

Re: A curious case of of my()
by ikegami (Pope) on Apr 05, 2011 at 15:17 UTC

    It's quite simple: Using a my variable without having first executed the my is a bug. By braking that rule, you break the "fourth wall" between the promised behaviour of my and its optimised implementation.

    my variables are created at compile time. Executing a my places a directive on the stack that will get executed on scope exit. The directive causes the variable to be cleared (if possible) or replaced (if a reference keeps it alive).

    If you want a static variable, use state.

      Thanks, I forgot about scope-exit behavior...

      Anyway I'm wondering why a post-fix if doesn't force a new scope, IMHO that would solve the problem in a consistent way:

      use strict; use warnings; $a=0; if ($a) { my $z=666; } my $y=666 if $a; print $y; # -> nothing print $z; # -> Global symbol "$z" requires explicit package na +me

      of course treating short circuit and in the same way could cause more complications.

      $a and my $x =666; print $x; # -> nothing

      At least this "it's a new scope" logic could be used to detect "my"-problems at compile-time and throw warnings.

      Cheers Rolf

      UPDATE: short-circuit and

        It wouldn't fix the following:

        foo() and my $x; foo() or my $x; foo() && my $x; foo() || my $x; foo() // my $x; foo() ? my $x : 1;

        Not to mention that some code relies on the current behaviour.

Re: A curious case of of my()
by kilocoder (Novice) on Apr 05, 2011 at 16:42 UTC
    $href is empty, since it is not passed into foo. hence @array ends up being a package variable and not a lexical variable.
    your code
    sub foo{ my $var = shift; my $href = shift; my @array = $href->{pass_in} if defined $href and exists $href +->{pass_in}; push @array, $var; print "contents : @array\n"; } foo(1); foo(2);
    This gives
    contents : 1
    contents : 1 2

    However, commenting out the unused href code and declaring array as a lexical like:

    sub foo{ my $var = shift; my @array; #my $href = shift; #my @array = $href->{pass_in} if defined $href and exists $hre +f->{pass_in}; push @array, $var; print "contents : @array\n"; } foo(1); foo(2);
    gives

    contents : 1
    contents : 2

    I hope for nothing. I fear nothing. I am free.
      $href is empty, since it is not passed into foo. hence @array ends up being a package variable and not a lexical variable.

      As others have pointed out, that's wrong. my creates lexicals at compile time. It doesn't have a our fallback. The 'if' modifier with a false condition inhibits the opcode which clears the lexical at runtime.

      our @array; # package vaiable @array = qw( foo bar ); sub foo{ my $var = shift; my $href = shift; my @array = $href->{pass_in} if defined $href and exists $href +->{pass_in}; push @array, $var; print "contents : @array\n"; } print "outer scope - contents : @array\n"; foo(1); foo(2); print "outer scope - contents : @array\n"; __END__ outer scope - contents : foo bar contents : 1 contents : 1 2 outer scope - contents : foo bar

      As you can see, the variable @array inside the sub is a lexical.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://897458]
Approved by Ratazong
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (12)
As of 2014-07-10 13:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (211 votes), past polls