Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

do, local and a qualified identifier?

by tomazos (Deacon)
on Oct 09, 2005 at 01:11 UTC ( [id://498483]=perlquestion: print w/replies, xml ) Need Help??

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

I have been handed a Perl script to work with that has a configuration file specified by a command-line argument.

The configuration file is selected based on the command-line parameter and then loaded with a do $config_filename in the main script.

In a given configuration file it says something along the lines of:

package Foo; use strict; use warnings; local ($Foo::bar); sub init { $Foo::bar = 42; }

Later on init gets called from the main script.

After that, what is the value of $Foo::bar in the main script and why?

What is the purpose of the declaring $Foo::bar local? I thought it gave it a global symbol a local value?

If so, when init is called will it set the localized value like a closure or the global value?

Further, what is the point of qualifying the identifier with the package name? and does that have any effect on the functionality?

Totally confused. Have not seen this way to do it before.

Update: Yes, we were getting the "$bar used only once" error when I changed it to use our and unqualified - even though bar is mentioned outside of the do. This is what confused me. Why do you get that error for an our and not for a local? I don't see it changing the number of times it is mentioned. (In fact, couldn't perl warn "useless use of local" in the above code, as the local does absolutely nothing.)

-Andrew.

Replies are listed 'Best First'.
Re: do, local and a qualified identifier?
by ikegami (Patriarch) on Oct 09, 2005 at 02:15 UTC
    I thought it gave it a global symbol a local value?

    It does, at run-time.

    • Foo.pm gets compiled.
    • Foo.pm's topmost level gets executed.
      • local $Foo::bar gets executed.
        • $Foo::bar current value (undef) is saved.
        • $Foo::bar is set to undef.
      • Anything else in Foo.pm's topmost level gets executed.
      • $Foo::bar reverts to undef. A file counts as block for scoping purpose, and we've just run to the end of the block in which local $Foo::bar was called.
    • &Foo::init is called.
    • &Foo::init sets $Foo::bar to 42. There's no local $Foo::bar in effect, so the value remains.
    What is the purpose of the declaring $Foo::bar local?

    None, unless it's used in Foo.pm's topmost level, or in a function (directly or indirectly) called from Foo.pm's topmost level.

    If so, when init is called will it set the localized value like a closure or the global value?

    It depends on whether someone in the call stack did local $Foo::bar. Unless &Foo::init is called from Foo.pm's topmost level (where there is such a local), probably not.

    Further, what is the point of qualifying the identifier with the package name? and does that have any effect on the functionality?

    Removing it will result in a compilation failure because use strict 'vars' is active. If you want to remove the need for the package quantifier, use our $bar; in scope at compile-time.

    use strict; use warnings; package Foo; our $bar; # "our" is like "my", but it # creates a package variable # instead of a lexical variable. sub init { $bar = 42; # "our" removes the need to # specify the package name. } ... 1;

      The last part of your post might misled people to think that our is a must for removing the syntax error. So just a little bit more detail...

      Remove the package qualifier, but keep local, it results syntax error:

      use strict; use warnings; package Foo; local $bar; sub init { $bar = 42; } 1;
      Global symbol "$bar" requires explicit package name at Foo.pm line 6. Global symbol "$bar" requires explicit package name at Foo.pm line 9. Global symbol "$bar" requires explicit package name at Foo.pm line 10. Foo.pm had compilation errors.

      But use either my or our removes the error:

      use strict; use warnings; package Foo; my $bar; sub init { $bar = 42; print $bar; } 1;

      But the use of our or my does make difference in other sense. The following script works when $bar is defined with our:

      use strict; use warnings; use Foo; Foo::init(); print $Foo::bar;

      But does not work if $bar is defined with my:

      Name "Foo::bar" used only once: possible typo at math1.pl line 7. Use of uninitialized value in print at math1.pl line 7.

      my or our? depends on what you want to do - in what scope you want your variables to be seen.

        yeah, but using my would render $bar inaccessible from the main program. Since the OP was asking for the value of $Foo::bar as seen from the main program, using my probably won't work. Thanks for the clarification, though.
Re: do, local and a qualified identifier?
by Aristotle (Chancellor) on Oct 09, 2005 at 02:05 UTC

    local scopes variables temporally, for the duration of execution of a piece of code.

    In the code you show, it executes on loading as part of the file’s main code. The function does not execute in the course of that invocation. After execution falls off the end of the file, the localisation is reverted.

    When the init function is called, the local’s effect is long forgotten, so the caller’s view of $Foo::bar is affected by the assingment.

    Strictly per your example, there is no point in localising the variable like that. I don’t know if it’s not sensible in the real code, though.

    Makeshifts last the longest.

Re: do, local and a qualified identifier?
by ysth (Canon) on Oct 09, 2005 at 03:53 UTC
    I'm guessing someone might have "syntax-checked" the file with perl -c filename, and added the local as a way (not a good way, though) to suppress the "Name "Foo::bar" used only once: possible typo at foo.pl line 3." warning. (The warning isn't given when the file is invoked via do $filename because a file used that way is likely to use variables set elsewhere and set variables used elsewhere.)

      The only time my comments will contain anything close to swearing is next to a no warnings 'once'; line at the top of my code, which is occasionally followed by # sod off. That warning is the single most useless thing ever – it has never ever caught a single mistake of mine but has inconvenienced me plenty.

      It might be useful for coding in the absence of the vars stricture (maybe?), but that’s the one stricture I always use.

      (I suppose you can tell it annoys me…)

      Makeshifts last the longest.

Re: do, local and a qualified identifier?
by ewilhelm (Novice) on Oct 09, 2005 at 07:09 UTC
    > what is the value of $Foo::bar in the main script and why?

    42. Because Foo::init() sets the package variable explicitly.

    As for the local(), that has no effect on the scope inside of the init.

    Is there something else happening in the larger context (or maybe that's a remnant of the boilerplate config where it is sometimes required?) It's probably the latter — an onion in the varnish.

    Qualifying with the package name? As opposed to setting the value of any random $bar? If you didn't declare it with our(), it won't work under strict.

      Whether init sets the variable explicitely or not has no bearing on the answer.
      Foo.pm ------ use strict; use warnings; sub init { print("Setting \$Foo::bar to 42.\n"); $Foo::bar = 42; } local $Foo::bar; init(); 1;
      main.pl ------- use strict; use warnings; use Foo (); print("\$Foo::bar = $Foo::bar\n");
      output ------ Setting $Foo::bar to 42. Use of uninitialized value in concatenation (.) or string at main.pl l +ine 7. $Foo::bar =
        >>Later on init gets called from the main script.
        >>After that, what is the value of $Foo::bar in the main script and why?
        
        >...explicitly...no bearing on the answer

        It does, just that the wrong question was asked. Note that your response (bullet point 4) compiles into the same neuroncode as mine.

        Your new example has reframed the problem into use() of a module, where the original question was about do() and it also also calls init() not from the main script, but from the module (where the local($Foo::bar) happens to be in effect.) The OP states that init() gets called from the main script. True, if the file getting do()ne calls init(), something similar to what you demo will happen.

        The point that I was trying to make is that the local() had absolutely no impact on what happens inside of init(), so the value of $Foo::bar follows the same rules that it would if the local() statement never existed.

        If the OP's actual code is truly like the sample, then this is simply a case of assuming that an artifact of accident or ignorance is is somehow attributable to design. I opted not to reimplement the documentation of do, our, local, perlsyn, and perlvar under the assumption that the OP was in possesion of said fine documentation. In this case, the simple answer that it is probably an onion in the varnish (while that varnish may, as ysth suggests, belong to perl) seems sufficient to inspire the OP with the required curiosity.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (3)
As of 2024-04-25 17:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found