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

Is there a way to scope a variable as "global to me and my children"

I have a subroutine that pulls some data. It makes some decisions about the data and then calls other subroutines to handle the data. It is a relativly large bit of data, so I don't want to pull the data again in the sub-subroutine. No one above the main subroutine needs these variables. I just want to share my variables with a routine that I call.

I am sure there is a way to do this. But how?

Thanks, Skip

Replies are listed 'Best First'.
Re: Scope Between global and my
by liz (Monsignor) on Apr 01, 2004 at 17:52 UTC
    References!

    my $foo = "long string\n"; bar( \$foo ); # pass reference sub bar { my $fooref = shift; print $$fooref; # dereference } __END__ long string

    Check out perlref and perlreftut.

    Liz

Re: Scope Between global and my
by jdporter (Paladin) on Apr 01, 2004 at 17:37 UTC
    localizing a global variable is a reasonable way to do this. By localizing it, the variable's former value -- if it even has one -- is stored away, and restored when your subroutine returns.
    If you want to be paranoid, you can select a special namespace for the variable, to make it unlikely that any other part of the program would even know about it. This will also silence any warnings you might get from use strict about global symbols requiring package names. (And you do use strict, don't you?)

    Example:

    sub main_routine { local @private::keep::out::data = load_huge_array(); child_sub1(); child_sub2(); } sub child_sub1 { for ( @private::keep::out::data ) { ... } }

    jdporter
    The 6th Rule of Perl Club is -- There is no Rule #6.

      Isn't local deprecated?

        Absolutely not! And I've illustrated a good use for it above.

        However, I suppose it depends on whom you ask. Some people believe that since "global variables considered harmful" for other, more primitive languages, it applies to Perl as well. I disagree.

        Global variables must be used with care, of course. But then, we should be careful in all our programming, no?

        jdporter
        The 6th Rule of Perl Club is -- There is no Rule #6.

        Use of local is not deprecated, but it's not for creating new lexical variables. It "suppresses" the existing value of an existing variable for the lifetime of a given scope.
        { local $x = 3; do_stuff(); }
        is functionally equivalent to:
        { my $secret_name_1095471 = $x; $x = 3; do_stuff(); $x = $secret_name_1095471; }
        The problem with local is that it LOOKS like some handy keyword for creating locally scoped variables. But some do_stuff() might not be expecting this suppression, and they might not realize that the suppression will end without their control. No matter what do_stuff() does, the value of $x will be reverted at the end of this code's scope.

        --
        [ e d @ h a l l e y . c c ]

Re: Scope Between global and my
by duff (Parson) on Apr 01, 2004 at 17:41 UTC

    You can create your own lexical scope by placing braces around the subroutines you want to access the variable.

    { my $data; sub foo { ... } sub bar { ... } }

    Alternatively, if these subroutines are related so closely, you might want to just create a separate package for them and use a package-global variable:

    package Foo; our $data; sub foo { ... } sub bar { ... } 1;
      I would only use the package-global variable if other packages (or main) must have access.

      In this case, just use a 'package' lexical:

      package Foo; my $data; sub foo { ... } sub bar { ... } 1;
Re: Scope Between global and my
by davido (Cardinal) on Apr 01, 2004 at 17:43 UTC
    It sounds as if you want to do something like this:

    # First, open a lexical block to hold the configuration variables. { # Now, open a configuration file to pull in data. my %settings; open my $config, "<configfile.dat" or die "Can't get started.\n$!"; while ( my $entry = <$config> ) { my ( $key, $value ) = split /\s+=\s+/, $entry; chomp $value; $settings{$key} = $value; } close $config; # Now, define the sub that will be the "getter" of # the lexical variables. sub mysub { print "Configuration file settings:\n"; foreach my $key ( %settings ) { print "$key = $settings{$key}\n"; } } # Next, close the lexical block. Only things within this block # will have access to the varibles declared with 'my' within it. } # This is the main program block: mysub();

    The sub "mysub()" will have access to the lexical variables within the outter block, but since the block terminates before you get to the main part of the program, nobody else will have access to them. This is the first step in building a closure, for example.


    Dave

      Ok, I can see how a lexical block can do this for contiguous code segments. But I see a possible future problem in keeping track of this. Not moving a sub out of the block, etc.

      what I would really like is to be able to say. Ok, when I start sub-b from sub-a, I want to run sub-b in the same data space as sub-a.

        Then you probably want to use packages to segregate namespace.

        Honestly, if maintainability is an issue, and you are afraid that a lexical block enclosing a couple of subs is going to turn out to be a nightmare to keep track of, you're reached that point where packages and modules are there help you keep it all straight.


        Dave

Re: Scope Between global and my
by dragonchild (Archbishop) on Apr 01, 2004 at 18:23 UTC
    Although there's hundreds of examples of this, the most recent one I've seen is the parsing engine for Text::xSV. You can view the source on CPAN. Look for the function parse and poke around.

    For the record, the method demonstrated is lexical scope.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose