Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

"if" in a my declaration statement causes problem

by ganeshk (Monk)
on Feb 20, 2006 at 13:20 UTC ( [id://531398]=perlquestion: print w/replies, xml ) Need Help??

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

Hi All, I have a very preliminary question. I have got into trouble a couple of times, when I use a statement like this
sub sub1 { .. my $x = $y if ( <some condition> ); .. }
What happens is that, the same value in $x seems to be cached once when sub1 is called and when sub1 is called again, the $x seems to be set with the same value even when it is not expected to be! Thanks, Ganesh

Replies are listed 'Best First'.
Re: "if" in a my declaration statement causes problem
by ysth (Canon) on Feb 20, 2006 at 13:33 UTC
    Um, Don't Do That Then?

    http://perldoc.perl.org/perlsyn.html:

    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.
    A short explanation of the behavior you are seeing: my has both a compile-time and run-time effect. At compile-time, it establishes a lexical variable for the remainder of the current scope, so any mention of the variable name is bound to an offset in an area known as the pad. All pads are initially set up with undefined variables. When a scope is exited, any lexicals that were actually used are reset to undef so they are ready for the next time the scope is entered. When the my is reached at run-time, it records that the lexical was used and needs to be cleared when the scope is left. By having the if there, you are preventing the my() from executing at run-time some of the time, so the scope-exit code doesn't know that the lexical was used, so it isn't reset to undef, so next time the scope is entered the previous value is still there.
      Thanks very much, ysth for the explanation.

      My dense skull isn't penetrating this issue. The original poster wrote ...

      Update: No, the original poster did not write what I claimed. The first response did.

      my $x; # one statement $x = $y if {condition;} # two statement
      the perlsyn you quoted is different
      my $x if ... presuming my $x = $y if {condition;}
      in his case. These seem to be different. You are holding up the perlsyn snip as an example says the two cases are synonyms. Why?

      In my testing of this, it works (perhaps version dependent?):

      sunorccws04 ~$ cat tpl ; ./tpl #!/usr/bin/perl sub showme; foreach $y ( 1..10) { $foo = $y; print showme(), "is the x value\n"; } sub showme { my $x; $x = $y if ($foo %2); # might as well mix up some T/F } 1 is the x value 0 is the x value 3 is the x value 0 is the x value 5 is the x value 0 is the x value 7 is the x value 0 is the x value 9 is the x value 0 is the x value
      getting strict "breaks" the behavior,
      sunorccws04 ~$ cat tpl ; ./tpl #!/usr/bin/perl use strict; my ($foo, $y); sub showme; foreach $y ( 1..10) { $foo = $y; print showme(), " is the x value\n"; } sub showme { my $x; $x = $y if ($foo %2); # might as well mix up some T/F } is the x value 0 is the x value is the x value 0 is the x value is the x value 0 is the x value is the x value 0 is the x value is the x value 0 is the x value
      predefining x as in  my $x = 0;, doesn't change the results. Changing the declaration of $y, $foo from my to our causes the code to behave like the non-strict version. But in all cases the results are consistant and predictable.

      ??

      Be Appropriate && Follow Your Curiosity
        My dense skull isn't penetrating this issue. The original poster wrote
        my $x; # one statement $x = $y if {condition;} # two statement
        Both when I posted and now, the OP reads: my $x = $y if ( <some condition> ); Are you looking at someone else's reply?

        With the my $x separate and unconditional, the warning in perlsyn doesn't apply.

        The output from your strict version doesn't make sense to me, offhand.

Re: "if" in a my declaration statement causes problem
by Siddartha (Curate) on Feb 20, 2006 at 13:30 UTC
    Rather do this:
    my $x; $x = $y if ( <some condition> );
    Otherwise, post a bit more code. What do you do with $x after that?
Re: "if" in a my declaration statement causes problem
by davidrw (Prior) on Feb 20, 2006 at 14:12 UTC
    The responses to this reply are enlightening (especially the one by bart which explains the "caching").
Re: "if" in a my declaration statement causes problem
by Irrelevant (Sexton) on Feb 21, 2006 at 12:37 UTC

    Another possibility, if you still wanted it on one line, would be:

    sub sub1 { #... my $x = ( <some condition> ) && $y; #... }

    This way, if the condition ended up false, you'd wind up with some false value (although not necessarily undef) in your variable. You could do my $x = ( <some condition> ) ? $y : undef; if you need $x to default to undef, but I'd say Siddartha's solution looks tidier for that case.

      I like your suggestion to use the ternary operator. In fact, it makes more sense than the high-precedence logical operator approach you outline above. The logical approach relies on short-circuit effects to work, and may not be obvious to future maintainers. The ternary operator is being used in its normal mode.

      Another issue with the logical approach is that when the condition is false, the value of $x becomes whatever scalar the condition evaluates to. This could lead to unexpected behavior where the condition may evaluate to an otherwise legal value for $x.

      my $y = 0; # ... Much code; my @list = (); # ... Much code my $x = @list && $y; # if $x is 0, did it come from @list or $y?

      If the OP wants to do a conditional assignment and declaration on one line, the following is, IMHO, unambiguously the way to go.

      sub sub1 { # ... my $x = <some condition> ? $y : undef; # ... }


      TGI says moo

Re: "if" in a my declaration statement causes problem
by mrpeabody (Friar) on Feb 21, 2006 at 23:06 UTC
    Combining "my" and "if" should issue a warning from the compiler. It's a gotcha, it's not intuitive behavior, and -- judging by how often it comes up on Perlmonks -- catches many otherwise able coders unawares.
      It should, yes. But don't expect it to in any 5.8.x release. The maint pumpking is very cautious about adding new warnings, and for a while there were a number of people advocating
      sub foo { my $x if 0; ... }
      to create a "static" variable, rather than using a closure
      { my $x; sub foo { ... } }
Re: "if" in a my declaration statement causes problem
by MonkPaul (Friar) on Feb 22, 2006 at 16:47 UTC
    As other people have said - i would set the value to nothing at the very start of the loop. Then initialise it to the input value after that so its a clean value each time. BUT, would set the variable after the condition is true:
    sub mehtod($) { my $y = @_; my $x = ""; # or my $x = 0; # then if(/expression/) { $x = $y; } }

    Thats my preferable way of doing thins though, which does exactly the same as yours but means 3 extra line of code - ooooooh!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://531398]
Approved by Corion
Front-paged by grinder
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (3)
As of 2024-04-26 06:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found