Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Conditional initialization of my-variables

by muthm (Sexton)
on Apr 06, 2023 at 23:30 UTC ( [id://11151499]=perlquestion: print w/replies, xml ) Need Help??

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

Wise monks,

I am having a strange and unexpected effect when I create a lexical variable using my in a subroutine, and initialize it conditionally using a 'statement modifier' condition.
In short, when I do this:

sub foo { ... my $var = "<value>" if <condition>; ... }

When I call the subroutine several times, with a changing condition, it seems that the my variable keeps its value from the previous call when the condition is false.
For example:
$ cat my_with_if.pl #!/usr/bin/env perl use strict; use warnings; use feature 'say'; use feature 'signatures'; no warnings 'experimental::signatures'; use Data::Dump qw( pp ); sub foo( $value ) { say "foo( ", pp( $value ), " )"; my $result = "default" if not defined $value; say "\$result after 'my' is ", pp( $result ); $result //= $value; say "\$result after '//=' is ", pp( $result ); say ""; return $result; } foo( $_ ) for ( "call 1.1", "call 1.2", "call 1.3", undef, "call 2.1", "call 2.2", "call 2.3", ); 1; $ ./my_with_if.pl foo( "call 1.1" ) $result after 'my' is undef $result after '//=' is "call 1.1" foo( "call 1.2" ) $result after 'my' is "call 1.1" $result after '//=' is "call 1.1" foo( "call 1.3" ) $result after 'my' is "call 1.1" $result after '//=' is "call 1.1" foo( undef ) $result after 'my' is "default" $result after '//=' is "default" foo( "call 2.1" ) $result after 'my' is undef $result after '//=' is "call 2.1" foo( "call 2.2" ) $result after 'my' is "call 2.1" $result after '//=' is "call 2.1" foo( "call 2.3" ) $result after 'my' is "call 2.1" $result after '//=' is "call 2.1"

Maybe I would have expected that behavior from a static variable, but not from a my variable.
What I would have expected is that the variable would be initialized with undef if the condition is false.

What is the reasoning behind this behavior? Thank you for helping me understand...!

PS: I know that I can get the undef initialization with

my $var = <condition> ? "<value>" : undef;
if I really want.
I am just curious! :-)

Replies are listed 'Best First'.
Re: Conditional initialization of my-variables
by kcott (Archbishop) on Apr 07, 2023 at 00:56 UTC

    G'day muthm,

    Take a look at ++hv's post from last week which discusses this issue. In particular, his "it acts something like a state variable" aligns with your "keeps its value from the previous call".

    The solution he presents is the same as the response you've already received from ++LanX; namely, separate the declaration from the conditional assignment.

    — Ken

Re: Conditional initialization of my-variables (runtime)
by LanX (Saint) on Apr 06, 2023 at 23:37 UTC
    Hi

    >

    my $var = "<value>" if <condition>;

    Yeah, that's a classic (and FAQ IIRC)

    Short answer: my has also an runtime effect° to default the value to undef .

    But that is bypassed here by the condition.

    Do this instead:

    my $var; $var = "<value>" if <condition>;

    update

    °) "undocumented implementation detail" may be more precise

    See also

    • perlsyn#Statement-Modifiers:

      NOTE: The behaviour of a my, state, or our modified with a statement modifier conditional or loop construct (for example, 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.

    Cheers Rolf
    (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
    Wikisyntax for the Monastery

      Alternatively,

      my $var = <condition> ? "<value>" : undef;
Re: Conditional initialization of my-variables
by eyepopslikeamosquito (Archbishop) on Apr 07, 2023 at 00:58 UTC

    Your example has reinforced my long-held support for Use block if not postfix if (as recommended in Perl Best Practices).

    Though a bit longer, I've always found block if to be clearer and easier to understand. The big win comes during code review whenever you want to add an extra statement to the if condition -- that's a simple one line change to a block if, compared to a more violent restructuring of the code from postfix if to block if.

    See also the first principle from Re: Big cache (my top ten software development practices):

    • Correctness, simplicity and clarity come first. Avoid unnecessary cleverness.

    and my longer Coding Standards Links.

      Your example has reinforced my long-held support for Use block if not postfix if

      Having struggled to understand code that I wrote just a few years ago that used postfix if conditions, I concluded that if I can't understand it quickly, anyone else would have great difficulty simply because they didn't write it. So now I almost exclusively use conditional blocks.

      The one major exception is where the condition modifies the condition variable:

      my $input = <STDIN>; $input = 10 if $input > 10;
      or to add a default value
      $input = 1 unless $input;

        > or to add a default value

        > $input = 1 unless $input;

        Careful! Many things are false in Perl, like 0 or ""

        You probably meant

        $input = 1 unless defined $input;

        Anyway, both are IMHO better written as

        $input ||= 1; # default if false # or $input //= 1; # default if undefined

        Cheers Rolf
        (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
        Wikisyntax for the Monastery

A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

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

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

    No recent polls found

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.