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

Hello, I have a question on using type globs. Namley, how does one use a typeglob and restrict the scope of the name mapping to a local scope. Apparently you cannot typeglob into a lexical variable.

longer explanation of the problem:

Those familiar with type globs will recognize the following conventional use:

@foo = ("initial"); *bar = \@foo; $bar[0] = "final"; print @foo;
this will print "final".

this inserts the referent to @foo into the array slot of the typeglob of bar, and thus @bar and @foo are refer to the same memory. thus the result

So far so good. Now I got into trouble here when I tried to use in combination with "strict vars", and incidentaly inside of a package.

Strict requires that I declare the variable @bar, and as near as I can tell there are three ways I can do this. "my @bar;" or "our @bar;" or "use vars qw/@bar/;" using "my @bar;" causes the incorrect, or rather unintended result, because as near as I can tell you cannot typeglob a lexical variable. What appears to happen is that the type glob creates a package variable @bar and links it to @foo, but then this variable is not accessible anymore as @bar since it is masked by the previously declared lexical variable. Thus the assingment $bar[0]=1 goes into the lexical @bar and not into @foo.

my @foo = ("initial"); use strict; my @bar; *bar = \@foo; $bar[0] = "final"; print @foo;
this prints "Initial"

using "our @bar;" does achieve the desired outcome of printing "final" and making @bar and @foo linked. However, it does so apparently at the cost of creating a package global variable rather than a locally scoped variable. So the question is how do I get a locally scoped variable, and use a type glob? Actual use example of what I'm trying to do:

package wombat; our @bar = ("haha"); # this is going to get # accidentally clobbered use strict; sub A1 { my @foo = (1,2,3,4); return B2(3,\@foo); # pass in reference to @foo } sub B2 { my ($n,$foo) = @_; # now instead of always indexing $foo as a reference, # I will use a type glob # to allow me to access it as though it were an array. # @bar here is intended to be just a temporary convenience # variable name. But it accidentally collides with # a package global used elsewhere. # my @bar; # cannot do this, which would logically # be locally scoped as I want it to be # and avoid stepping on package globals. our @bar; # must do this instead, which because of #an accidental name collision with the # package global that is also called # "@bar", is going to have a sideeffect. *bar = $foo; # now do something with @bar # --this is just a trivial placeholder process @bar = map { sin($n+$_) } @bar; return $bar[0]+$bar[4]; # just a trivial placholder } print A1(); # prints the expected result print @bar; # but @bar is no longer "haha". # because it gets clobbered because # I could not control the scope of the typeglob

Replies are listed 'Best First'.
Re: Type globs, strict, and lexical variables
by ikegami (Patriarch) on Jul 17, 2006 at 04:47 UTC

    I think you are looking for:

    { local *bar # Make sure we don't clobber an existing var. *bar = \@foo; # Create an alias our @bar; # So we don't have to say @Package::bar. print($bar[0]); # Same as print($foo[0]); } # Restores *bar (and therefore $bar, @bar, etc)

    The first two lines can be combined:

    local *bar = \@foo;

    Alternativly, Data::Alias allows one to lexical aliases.

      Cool! never would have thought I could localize a typeglob itself. Hmmmm... will this really work, since you can't localize a variable that doesn't pre-exist, under strict.
        you can't localize a variable that doesn't pre-exist, under strict.

        That's not true. strict has nothing to do with local. For example,
        perl -Mstrict -e "local $Package::foo"
        give no error.
        perl -Mstrict -e "local $foo"
        gives an error, but so does
        perl -Mstrict -e "$foo"

        will this really work

        Strict doesn't apply to globs (since they can't be declareds), so
        perl -Mstrict -e "*foo"
        and
        perl -Mstrict -e "local *foo"
        give no error.

      yep! this works like a charm.
      perl -we 'use Strict; our $r="foo"; my $f = "boot";{local *r =\$f; $r += "loop"; print "$f\n$r\n...\n"};print print "$f\n$r\n...\n"' __output__ loop loop ... loop foo ...
      Thanks a lot. I learned something interesting.
      I spoke too soon. using local still soes not present accidental clobbering:
      my $f = "boot"; {local *tmp =\$f; $tmp = "loop"; GG::cc () ;print "$f\n...\n"}; sub cc { $tmp="cc did it"}; print "$f\n...\n";
      sub cc, happens to use the same dummy variable name $tmp. as a result as the local expression $f gets clobbered. What I want is something that makes $tmp scoped like a my variable.

      THe problem I am trying to solve here is simply to always have to write de-reference code when I pass in a reference. I want an alais in the form of a localy scoped variable to the object being dereferenced. It looks like you might be able to do this with a tie or with Data::alias but those are both very heavyweight solutions.

        strict won't let you do that.
        use strict; sub test { my $f = "boot"; local *tmp = \$f; print("$tmp\n"); # boot our $tmp = "loop"; print("$tmp\n"); # loop test2(); print("$tmp\n"); # loop } sub test2 { #$tmp = "test2 did it"; # XXX strict error my $tmp = "test2 did it"; # lex var alternative local our $tmp = "test2 did it"; # pkg var alternative } test();

        Yes, test2 can change the value of $tmp, but only if test2 doesn't properly localize its variables. Perl gives you plenty of ways of shooting yourself in the foot, but they can all be avoided easily and safely with a little care. In this case, that means local shoule be used whenever our is used, unless there is a need to modify the variable in the parent scope.

        Data::Alias isn't that heavyweight I think... I know it's a bit largeish module, but unlike tie() its use imposes virtually no overhead at runtime, and very little at compile time (no source filter).

        And it solves your problem nicely, and probably more efficiently than anything involving typeglobs:

        alias my @bar = @$foo;

        UPDATE: It actually benchmarks faster than local *bar = $foo on my machine, with the benefit of being truly lexically scoped.

        sub cc, happens to use the same dummy variable name $tmp.
        But dummy variables should always be lexicals. In fact, I don't think you've absorbed the concept that everything possible (which is just about everything) should be lexical. Are you dealing with legacy code?
Re: Type globs, strict, and lexical variables
by davido (Cardinal) on Jul 17, 2006 at 04:52 UTC

    Typeglobs live in the package namespace. A typeglob is the 'name' and the various package variable containers (scalar variable, array variable, hash variable, filehandle, and so on) that will be associated with that name. Symbolic references can dial in to typeglobs and package variables, because symbolic refs are simply a means of accessing the package global namespace.

    Lexicals don't have a 'namespace' or a package. They're, as their name implies, lexically scoped. They live in a different sort of pad, and are not accessible via typeglobs nor via symbolic refs.

    You're correct that a lexical variable can mask a package variable. ...at least, that is if you only refer to the 'unqualified' package variable name. Consider this: In package main, a package global named $foo is really named $main::foo. That means that *foo is *main::foo. And that our $foo is also $main::foo. So if you have a package variable named $foo, in package main (thus also known by its fully qualified name as $main::foo), even if you declare my $foo;, thus masking the package variable $foo, you can still access the package variable by its fully qualified name: $main::foo.

    But lexical (my) variables don't have a package, and don't reside in the package symbol table (a glorified hash, by the way). They have their own terms of existence, and thus are not tied to typeglobs.

    If you want a more comprehensive understanding, better written and probably more accurate than my post here, do have a look at each of the following POD: perlref, perldata, and definitely perlsub. It's not a simple topic, but eventually vital toward understanding Perl.


    Dave

Re: Type globs, strict, and lexical variables
by perrin (Chancellor) on Jul 17, 2006 at 05:02 UTC
Re: Type globs, strict, and lexical variables
by cems2 (Novice) on Jul 17, 2006 at 04:33 UTC
    I note also I've considered the possiblity of using "local @bar" . but this simply moves the problem rather than solving it. You can't use "local @bar" without having another "our @bar" somewhere else. THus if two subroutines accidentally try to use the same named variable the theo "our" declarations will conflict.