http://qs321.pair.com?node_id=141365


in reply to Can you create *real* global variables?

Sounds like an interesting problem... If you don't use strict you can probably do the equivilent of importing the var from the main package into all subpackages of main that exist at that point in time. You could probably do this with an INIT block that inspects and modifies the symbol table. This, however, won't work for code that runs at compile-time. It also won't work for packages created at run time.

BEGIN { %main::_shared_vars = ( the_very_global => \$the_very_global ); } INIT { package main; sub _iterate_packages_loop { my($stash,$name,$callback) = @_; $callback->($stash,$name); foreach (keys %{$stash}) { if (/::\z/ and $_ ne "main::") { _iterate_packages_loop($stash->{$_},$name.$_,$callback); } } }; sub _iterate_packages { _iterate_packages_loop(\%::,"main::",shift); } _iterate_packages(sub { $_[1] eq "main::" and return; while (my($k,$v) = each %::_shared_vars) { $_[0]->{$k} = $v; } }); } $the_very_global = "GLOBAL!\n"; print $the_very_global; package bar; print $the_very_global; package bar::foo; print $the_very_global;

Fixing this technique to work with use strict can be done by overriding the strict pragma. One can even override it such that strict works as a source-filter that detects package usage and imports the variables appropriately before the code using them is compiled, so most of the advantage of using strict is not lost. I also use caller so if one does package Foo; use strict; it will still work. use strict; package Foo; (on one line) is not likely to work, however.

BEGIN { %main::_shared_vars = ( the_very_global => \$the_very_global ); } BEGIN { use Filter::Util::Call; use strict; my $_strict_import = \&strict::import; package strict; sub _add_to_stash { my $name = shift; no strict 'refs'; while (my($k,$v) = each %::_shared_vars) { # importing this way makes the variable # be considered "declared" for the purposes # of strict. *{$name."::$k"} = $v; } }; *strict::import = sub { # setup the package we are being called by _add_to_stash(scalar caller); filter_add(sub { my $status; while (($status = filter_read()) > 0) { _add_to_stash($1) while /package\s+([\w:]+)/g; last unless(/package\s*\z/); } return $status; }); goto &$_strict_import; }; }

Note that this code doesn't do very smart parsing of package names. I think that's okay since getting false positives is not really a problem. A combination of these two strategys should work except for compile-time run code that doesn't use strict and run-time generated packages that don't use strict. Note that the strategy used with strict can be applied to any module.

There are probably other ways to do this too. The debugging mechanisms may be able to obtain the necessary information to check for package declarations in files after they are loaded and before they are compiled. Alternately, one could write a source filter that does good parsing of perl (Text::Balanced would be helpful) and find all the package declarations and recode requires, dos, evals, uses etc. into something that would also check for package statements appropriately. (The filter would presumably be setup with the main program and work it's way from there.) This would probably be much, much harder than any of the methods mentioned here, though it would be more effective.