Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

creating a new symbol table glob

by ysth (Canon)
on Nov 02, 2003 at 19:48 UTC ( [id://303947]=perlquestion: print w/replies, xml ) Need Help??

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

I want to temporarily replace a symbol table glob *foo with a new glob (never mind why) such that \*foo has a new value. There doesn't seem to be a way to do it. Every way to assign to the glob just updates the GP, not actually replacing the glob:
*foo = *bar; *foo = Symbol::gensym *foo = \*bar; local *foo;
None of those work. This works, but marks all the globs in the stash as FAKE, with disastrous consequences:
%pkg:: = (foo => *bar, %pkg::);
Any clues short of XS?

Update: Ok, the obvious solution finally occured to me:

package pkg; $save_old_foo = \*foo; delete $pkg::{foo}; *{"pkg::foo"} or 0; # make perl create a new glob ...code using replaced glob goes here... delete $pkg::{foo}; *pkg::foo = $save_old_foo;
except that there seems to be no way to restore the glob to its original state. The above will put it at a different memory location.

Update: judging by votes, I seem to have intrigued some people. My end use ended up somewhat pointless in the end, but I may post a meditation on it when I have some time. It involved sub {}'s undocumented interaction with *__ANON__.

Replies are listed 'Best First'.
Re: creating a new symbol table glob
by jql (Acolyte) on Nov 03, 2003 at 00:53 UTC
    You're overworking the problem a bit, I think.
    package pkg; print \*{"pkg::foo"}; { local %pkg::; print \*{"pkg::foo"}; } print \*{"pkg::foo"};
    The only problem is that perl compiles in glob addresses when it knows them, so only symbolic references acknowledge the new glob address. For instance, try this:
    { package pkg; local %pkg::; print \*{"pkg::foo"}; print \*foo; }
    They *should* have the same address, but they don't since the address looked up at compile-time.
      Thanks, I think only something that does local %pkg:: is going to work. Putting everything else back in the local %pkg:: is the next step. Something like this (not yet tested):
      my $opkg = \%pkg::; local %pkg::; $_ ne "foo" and *{"pkg::$_"}=$opkg->{$_} for keys %$opkg;
      I can't decide if this is so hard because globs are such strange scalars or because symbol tables are such perfectly ordinary hashes.

      (About the compile-time lookup of globs, I remember once seeing a quote from Larry complaining about an optimization that made globals faster but not lexicals. Making every global reference look up the glob afresh sure would be a hearty encouragement to always use lexicals. :)

        Hmm..........
        { $foo::bar = "Show me"; print \*{"foo::bar"}; local %foo:: = %foo::; print \*{"foo::bar"}; print ${"foo::bar"}; # runtime lookup }
        Looks like that's enough. Your big problem is that even changing the glob addresses has no effect in the rest of the program, since perl never looks up symbol-table entries at runtime unless you use a symbolic ref. There is very limited functionality to replacing the glob entries in the symbol-table, since you must use it like a hash in order to see the effect.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (6)
As of 2024-03-19 05:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found