Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"

How to localize conditionally?

by saintmike (Vicar)
on Mar 13, 2011 at 19:52 UTC ( #892986=perlquestion: print w/replies, xml ) Need Help??

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

I'm using a library that acts on an %ENV variable being either set or not set. So, when I call it, I use

local $ENV{BLAH} = 42; libcall(); sub libcall { if( exists $ENV{BLAH} ) { print "env set to $ENV{BLAH}\n"; } else { print "env not set\n"; } }

and all is well, because the code within libcall() now sees $ENV{BLAH}'s value, while other parts of the system (outside the scope of the snippet above) aren't affected by the setting.

But now I want to add a condition in my code, to perform the setting only when another condition is met, but I can't use

if( condition() ) { local $ENV{BLAH} = 42; } libcall();

because the 'local' directive ends with the scope of the if-body and libcall() won't see it. I can't set the variable to undef because the library checks if the value exists(). I could obviously do

if( condition() ) { local $ENV{BLAH} = 42; libcall(); } else { libcall(); }

but that's lame because of the code duplication.

Is there a better way to 'local'ize a variable conditionally?

Replies are listed 'Best First'.
Re: How to localize conditionally?
by Corion (Patriarch) on Mar 13, 2011 at 20:00 UTC

    You could use goto or the blockless version of if:

    local $ENV{BLAH} = 42 if $DO_MAGIC; libcall();


    goto LIBCALL if (! $DO_MAGIC); local $ENV{BLAH} = 42; LIBCALL: libcall();
Re: How to localize conditionally?
by BrowserUk (Patriarch) on Mar 13, 2011 at 20:16 UTC

    Any reason why you can't pass the value into libcall() directly rather than via a localised %ENV element? (Which seems a strange way to do things?)

    sub libcall { my $arg = shift; if( $arg ) { print "Arg is $arg\n"; } else { print "Arg undefined\n"; } } libcall( condition() ? 42 : undef );

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      I just used libcall() to illustrate what's going on within the library. The real library is of course different and doesn't accept the value on its parameter list, but insists on getting it in %ENV.

      "What is this library, who in their right mind would support an interface like that!", you ask now! and I'll let you in that the library is Crypt::SSLeay and the variable is HTTPS_CA_FILE.

Re: How to localize conditionally?
by JavaFan (Canon) on Mar 13, 2011 at 20:40 UTC
    local $ENV{BLAH} = condition ? 42 : $ENV{BLAH};
      The library checks for existence, so that doesn't work. You'd need
      local %ENV = condition ? (%ENV, BLAH=>42) : %ENV;

        Did you test it? It works for me.

        - tye        

Re: How to localize conditionally?
by wind (Priest) on Mar 13, 2011 at 19:58 UTC
    { local $ENV{BLAH} = 42 if condition(); libcall(); }
Re: How to localize conditionally?
by ELISHEVA (Prior) on Mar 14, 2011 at 05:13 UTC

    Personally, I'd go with JavaFan's solution if you only have one environment variable and autovivification "risk" is not a concern to you (see replies to JavaFan's response above). I like the way it keeps the impact of the condition clearly focused on the variable and also makes clear the possible values.

    Although this code

    if( condition() ) { local $ENV{BLAH} = 42; libcall(); } else { libcall(); }

    is overkill for a single state variable, you might want to consider it later on, if it turns out that you have to set up multiple state all tied to the same condition. Were you to avoid the "if", and repeat the condition for each environment variable you need to set, you might well have a code duplication problem.

    On the other hand, I'd be hard pressed to call a single statement containing a parameterless subroutine call "code duplication". Code duplication (don't repeat yourself) typically applies to expressions with "movable parts": a single call with a long parameter list, multiple expressions passed as parameters, a conditional assignments ($x= COND ? A : B)or multiple lines of code. In these cases replication is problematic because multiple expressions and statements with identical internal logical are repeated. If the internal logic in one is buggy, all will be buggy and need to be fixed.

    However, a single parameterless function call has no internal moving parts. There are no "debug everywhere issues". Either you named the function correctly in a particular location or you didn't and that is about the limit of the debugging effort.

    Update: added comment about autovivification risk.

Log In?

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

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2023-12-03 01:34 GMT
Find Nodes?
    Voting Booth?
    What's your preferred 'use VERSION' for new CPAN modules in 2023?

    Results (20 votes). Check out past polls.