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

When trying to use typeglob for aliasing purposes, I ran into a strange behavior. I wonder if someone could explain the logic behind.

The following code (trying to access the hash directly as %foo) does not work:

use strict; use warnings; my $hashref = { "key" => "value" }; local *foo = $hashref; printf("keys=%d\n", scalar(keys(%foo)));

I get both 'Variable "%foo" is not imported' (which I find weird) and 'Global symbol "%foo" requires explicit package name' (which explains the problem). So far so good.

Attempting to use "my", the code now executes (with a warning: 'Name "main::foo" used only once: possible typo') but I do not get the expected result:

use strict; use warnings; my $hashref = { "key" => "value" }; my %foo; local *foo = $hashref; printf("keys=%d\n", scalar(keys(%foo))); # prints: keys=0

Using "our" instead of "my", I do get the expected result:

use strict; use warnings; my $hashref = { "key" => "value" }; our %foo; local *foo = $hashref; printf("keys=%d\n", scalar(keys(%foo))); # prints: keys=1

Could someone please explain why the "my" version is good enough to make Perl happy while still returning an unexpected result?

Replies are listed 'Best First'.
Re: typeglob & my | our
by LanX (Saint) on Mar 07, 2012 at 13:26 UTC
    This Typeglob-mechanism for aliasing is restricted to package variables (our) only.

    Lexical variables (my) have no builtin (general) aliasing mechanism.

    UPDATE:

    For the records, there is a hack (!) to alias lexical scalars by using one element for loops:

    for my $alias ($orig) { ... }

    another workaround would be to use tie.

Re: typeglob & my | our
by JavaFan (Canon) on Mar 07, 2012 at 14:35 UTC
    my %foo creates a lexical PAD entry. our %foo creates a stash, with %foo a lexically scoped name for the hash entry in said stash.

    *foo is that stash (imagine lots of hand waving here).

    When you later to keys %foo, Perl first goes hunting in the PAD for a lexical hash, if not found, it looks in the stash. In the variant you're doing my %foo, Perl will take the one from the PAD, which is empty. Without the my %foo Perl finds the %foo you want.

    Could someone please explain why the "my" version is good enough to make Perl happy while still returning an unexpected result?
    If you mean by "making Perl happy", "strict doesn't throw an exception", do realize that strict isn't an magic bullet. Strict is like having a car whose motor will not start if your door isn't closed, and your seat belts aren't locked when turning the key. Warnings are the beeping sounds your car will make as soon as you drive above 55 miles per hour. Neither of them prevents you from running full speed into a tree, or ending up in the Bronx while your intention is to go to Vegas.
      > *foo is that stash

      hmm ... in my terminology *foo is a _typeglob_ for the _symbol_ foo having slots for variables like %foo or $foo.

      But the STASH (= symbol table hash) is the surrounding hash (associated to a package e.g. %main::) holding such symbols.

      see also "symbol table" in perlglossary

      Cheers Rolf

      UPDATES: added link and "slot"-part

        Imagine that while I'm doing the indicated handwaving, LanX is in one of my hands.
Re: typeglob & my | our
by ikegami (Patriarch) on Mar 08, 2012 at 02:19 UTC

    The fact that you changed the variable associated with package variable %main::foo has no bearing on the contents of lexical var %foo.

    use strict; use warnings; my $hashref = { "key" => "value" }; my %foo; local *foo = $hashref; # Short for *main::foo printf("keys=%d\n", scalar(keys(%main::foo))); # keys=1 printf("keys=%d\n", scalar(keys(%foo))); # keys=0