4

In Perl the following code is very common. You can even see it in things like constant.pm.

my $symtab;
{
  no strict 'refs';                                                                                                                              
  $symtab = \%{$pkg . '::'};
}

If I simply delete strict, I get

Can't use string (main::) as a HASH ref while "strict refs" in use

Is it possible to do this at all, without turning off strict?

Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
  • 1
    Well, you *have* to do it without strict. You mean why would I do with strict? Because I like strict I guess and I need access to the symtab, and I just wanted to know if there is a less hacky way to do this? – Evan Carroll Nov 06 '19 at 15:53
  • 4
    Disabling `strict` in a small, lexical scope is exactly the right thing to do here in my opinion. It is meant to stop you from doing these kinds of things, so disabling this part of the strict policy explicitly is supports that, and tells readers of the code you knew what you were doing. – simbabque Nov 06 '19 at 15:56
  • You could certainly do it with XS code. Maybe there's a `B` based solution that can run under `strict`, too. – mob Nov 06 '19 at 16:25

3 Answers3

4

Strict does not prevent access if you don't need to construct the stash name:

use strict;
use warnings;
$Foo::Bar::baz = 42;
my $symtab = \%Foo::Bar::;
print "${$symtab->{baz}}\n";

You can also access it via the stash hierarchy without violating strict (it's globs all the way down):

use strict;
use warnings;
$Foo::Bar::baz = 42;
my $main_stash = \%::;
my $Foo_stash = $main_stash->{'Foo::'};
my $FooBar_stash = $Foo_stash->{'Bar::'};
print "${$FooBar_stash->{baz}}\n";

Package::Stash provides a programmatic way to access stashes.

use strict;
use warnings;
use Package::Stash;
$Foo::Bar::baz = 42;
my $package = 'Foo::Bar';
my $stash = Package::Stash->new($package);
print "${$stash->namespace->{baz}}\n"; # dereferencing the glob to access the scalar slot
print "${$stash->get_symbol('$baz')}\n"; # retrieving the scalar slot of the glob directly

Caveat emptor: just because strict vars does not prevent stash hierarchy access does not mean this isn't hacky (and resistant to compile time optimizations), and in most cases just turning off strict 'refs' and constructing the symbol name is preferred.

Grinnz
  • 9,093
  • 11
  • 18
  • But to be clear here, given the name of the package name, getting access to the symbol table for that package requires "constructing" it (ie appending `::`) which is a violation of strict mode? – Evan Carroll Nov 06 '19 at 17:57
  • Not necessarily; you can find it in the parent stash as well but it's a little convoluted; will update answer. – Grinnz Nov 06 '19 at 18:07
2

It's impossible to do with without turning off strict. But there are ways to hide that complexity. There are several modules that allow you to do this without actually turning off strict yourself - Symbol (included in the standard distribution), Symbol::Get and Tie::Symbol are three examples.

Dave Cross
  • 68,119
  • 3
  • 51
  • 97
1

Disguising the fact that you are doing something that isn't strict-safe by finding a way to do with with strict on is only fooling yourself and your readers. And that's a bad idea.


First of all, it's not very common. It's done by a few low-level modules. The normal Perl programmer will never manipulate the symbol table directly.

And yes, it is possible to do this without disabling strict. The symbol table is accessible via %::, so you could parse the package and navigate the symbol table that way. For example, \%{'Foo::Bar::'} becomes \%{ $::{"Foo::"}{"Bar::"} }, although that presupposes the existence of the package. You could also generate Perl code and use eval.

BUT, there's no reason to do so. One turns on strict specifically to prevent oneself from accidentally doing this. Disguising the fact that you are doing something that isn't strict-safe is only fooling yourself and your readers. And that's a bad idea. One should strive to write self-documenting code, and nothing says "this is tricky, dangerous code" like no strict 'refs';.

ikegami
  • 367,544
  • 15
  • 269
  • 518