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

Once again, my needs outstrip my knowledge. This time it has to do with what 'defined()' is really telling me in the following:
our $DoDebug = 1 ; no strict 'refs'; sub dynConf{ # args are like "DoDebug" , 0 my ($varName, $varVal) = @_; if ( defined ${$varName}){ # $DoDebug in symbol table ${$varName} = $varVal; # DoDebug=0; }else{ say "Variable $varName is not defined"; } }
This works, both the assignment and the detection of non-pre-defined variables. I am hoping that the 'defined' test is telling me that there is a symbol table entry named "DoDebug". This way I don't create variables that no one needs or will user. This is a generalized routine to modify arbitrary switches on the fly, without having to create separate little subroutines.

So the next thought is that if this works, can I use the same mechanism to make a package more aware of it's environment with a test like:

... if ( defined $Main::VerboseLogging) { # some detailed logging } --or-- if (defined BlackList::){ # the Blacklist.pm package is loaded as well }
Is there a general syntax to addressing the symbol table? Links and references are welcome...
It is always better to have seen your target for yourself, rather than depend upon someone else's description.

Replies are listed 'Best First'.
Re: flavors of "defined"
by moritz (Cardinal) on Feb 02, 2009 at 21:28 UTC
    Symbol tables are described in perlmod.

    In general if you have a package Foo::Bar, its symbol table is accessible as %Foo::Bar::.

    Oh, and you might want exists instead of defined in some cases...

Re: flavors of "defined"
by jethro (Monsignor) on Feb 02, 2009 at 21:28 UTC

    You might be looking for ref()

    > perl -e '$u='hallo'; print ref($u),"\n"; ' > perl -e '$u=\'hallo'; print ref($u),"\n"; ' SCALAR

    UPDATE: Misread your question. You are looking for the symbol table hashes

    > perl -e ' if (exists $main::{"u"}) { print "yes\n"; } ' > perl -e '$u='hallo'; if (exists $main::{"u"}) { print "yes\n"; } ' yes
Re: flavors of "defined"
by gone2015 (Deacon) on Feb 03, 2009 at 18:04 UTC

    You need to tread carefully around a couple of issues:

    • autovivification... if you ask defined(${'foo::bar::cantona'}) then the symbol table %foo::bar:: will pop into existence, if it does not already exist -- the variable $foo::bar::cantona, however, does not.

    • it is not always possible to tell the difference between $foo::bar::cantona not existing, and existing but being undef

    The following avoids the autovivication issue, by starting in the root symbol table (%main::) and proceeding towards the full name:

    sub edef { my ($symbol) = @_ ; no strict 'refs' ; my @path = split('::', $symbol) ; my $name = pop @path ; if (@path == 0) { @path = split('::', (caller)[0]) ; # use caller's package if no +ne given } ; if (($path[0] eq '') || ($path[0] eq 'main')) { shift @path ; # '::' => 'main::' and we start at 'main::' any +way } ; my $r_table = \%main:: ; foreach my $part (@path) { $part .= '::' ; if (!exists($r_table->{$part})) { return 0 ; } ; $r_table = $r_table->{$part} ; } ; if (!exists($r_table->{$name})) { return 0 ; } ; return defined(${$symbol}) + 2 ; } ;
    this takes the full name of a symbol (e.g. 'foo::bar::cantona')returns 0 if the symbol table doesn't exist, or no symbol of the given name exists in the symbol table. It returns 2 if the name exists, but 3 if the name exists and the related scalar value is defined.

    Note that if (say) @foo::bar::cantona exists, then 2 is returned if $foo::bar::cantona does not exist, and also if it exists but is undef. I know of no way around this ambiguity.

Re: flavors of "defined"
by Tanktalus (Canon) on Feb 04, 2009 at 00:54 UTC

    Seriously, don't.

    Use a global hash of values instead, if you're going to do that at all. You still don't need to create separate little subroutines, though if you did, it wouldn't really be that bad.

    my %globals = map { $_ => undef } qw/ all allowed names here including + DoDebug /; sub dynConf { my ($name, $val) = @_; if (exists $globals{$name}) { $globals{$name} = $val; } else { die "Huh? No such variable: $name"; } } # create the get-functions for (keys %globals) { # probably could do this without eval STR, but let's keep it simple eval "sub get_$_ { $globals{'$_'} }"; } # or just one get-function sub get_global { my $name = shift; if (exists $globals{$name}) { $globals{$name} } else { die "No such global: $name"; } }
    Really, is that so bad?