I want to stash a value into a package variable. Complications: The stashee is a different package from "me", __PACKAGE__; and at compile time, I only have the stashee's package name as a variable. So this won't work:
$Teddy::foo = 'cash';
It won't work because I don't know 'Teddy' when I'm writing the code.
Here's a little demo script that DWIW:
use strict; use warnings; use feature 'say'; { package Teddy; } package main; no strict 'refs'; my $ns = 'Teddy'; my $glob = *{"${ns}\::foo"}; say ' $glob: ', $glob; say '$Teddy::foo: ', $Teddy::foo; my $cram = 'cheese'; say ' $cram: ', $cram; ${ *{"${ns}\::foo"} } = $cram; say '$Teddy::foo: ', $Teddy::foo; my $yank = ${ *{"${ns}\::foo"} }; say ' $yank: ', $yank; __DATA__ Output: $glob: *Teddy::foo Use of uninitialized value $Teddy::foo in say... $Teddy::foo: $cram: cheese $Teddy::foo: cheese $yank: cheese __END__
The important code is ${ *{"${ns}\::foo"} }. The stashee (here 'Teddy') is stored in the variable $ns. Although Teddy is completely empty and innocent of anything, the cheese gets put in his belly.
Note that this is a somewhat strange thing to do, definitely nonstandard. It uses a symbolic reference and a package variable and it pollutes Teddy's namespace aggressively. But it does work.
The reason for this, in short, is that my code is going to do sekret stuff that must be parameterized at compile time. At run time, caller will call my code without the opportunity to pass the parameter explicitly. If I store the value of that parameter inside my own code, then either I have to make its value global to all callers or I have to store it in a hash keyed to caller. That last idea risks a memory leak, since I don't have any real way to know when caller has absolutely finished executing. Stashing the parameter in caller's namespace at compile time means I can drag it out later without ill effect and it will be destroyed when caller exits.
Note that although the demo script will run under -W, actual code probably will not (mine doesn't). The scope that stashes is a different scope from that which grabs; otherwise why bother? So when the stashing sub exits after the line:
${ *{"${ns}\::foo"} } = $cram;... the warning is emitted: Name "Teddy::foo" used only once: possible typo...
Any actual code that does the stash will need:
no strict 'refs'; # disable complaint about symbolic referen +ce no warnings 'once'; # disable complaint about var only used on +ce ${ *{"${ns}\::foo"} } = $cram;
... after which both strict and warnings should be re-enabled.
Fix all the clever stash code (per, IIRC, bart) to eliminate the concatenation.
Restore, with some trepidation, the paragraph of rationale.
Explain the warnings issue.
Fixed dropped right braces per almut.
Well, an interesting battle between the symbolic ref and the symbol table access. Meanwhile, in my current code, I've gone to the %state_of approach after all, in which I don't stash into caller's namespace but instead store in my own pseudo-global lexical.
On reflection (rarely unwise), I realized that nobody is going to use() my module so many times in one script that allocating (and never releasing) a little state for it will consume an appreciable amount of memory. It is, technically, a memory leak and one might consider that if one were to execute in a persistent environment.
You may still have a desire to stash; if so, you're welcome.
|
|---|