SUMMARY
At this point, after fairly extensive research, I am of a firm opinion that in a situation when a symbol table entry with the name "X" was declared but not assigned to, it is impossible to generically distinguish which of the reference types in a glob was actually declared witout using deep probing of Devel:: stuff.
In other words, you can tell only the following 2 distinct situations:
X was not declared at all (symbol table entry does not exist)
X was declared and some of the glob types were actually assigned to.
In this second case,
You can find WHICH of the glob types were assigned to and which were not
BUT, you can not figure out which of the non-assigned-to glob types were declared-and-unassigned vs. which were not declared at all.
In other words, for our $f = 1; our @f;
; we can tell that $main::f
is a scalar;
but we can NOT tell whether @f
and %f
were declared or not - it is not distinguishable at all from our $f = 1; our %f;
.
Please note that the subroutine definitions follow this second rule as well, but declaring a named sub automatically assigns it a value (the code block), so you can never have a sub name in a "declared but not assigned to" state (caveat: might not be true for prototypes??? no clue).
ORIGINAL ANSWER
Well, very limited (and IMHO somewhat fragile) solution to distinguishing a scalar from a subroutine could be to use UNIVERSAL::can:
use strict;
our $f;
sub g {};
foreach my $n ("f","g","h") {
# First off, check if we are in main:: namespace,
# and if we are, that we are a scalar
no strict "refs";
next unless exists $main::{$n} && *{"main::$n"};
use strict "refs";
# Now, we are a declared scalr, unless we are a executable subroutine:
print "Declared: \$$n\n" unless UNIVERSAL::can("main",$n)
}
Result:
Declared: $f
Please note that {SCALAR}
does not seem to work to weed out non-scalars in my testing - it happily passed through @A
and %H
if I declared them and added to the loop.
UPDATE
I tried brian d foy's approach from Chapter 8 of "Mastering perl" and somehow was unable to get it to work for scalars, hashes or arrays; but as noted below by draegtun it works for subroutines or for variables that were assigned to already:
> perl5.8 -we '{use strict; use Data::Dumper;
our $f; sub g {}; our @A=(); sub B{}; our $B; our %H=();
foreach my $n ("f","g","h","STDOUT","A","H","B") {
no strict "refs";
next unless exists $main::{$n};
print "Exists: $n\n";
if ( defined ${$n}) { print "Defined scalar: $n\n"};
if ( defined @{$n}) { print "Defined ARRAY: $n\n"};
if ( defined %{$n}) { print "Defined HASH: $n\n"};
if ( defined &{$n}) { print "Defined SUB: $n\n"};
use strict "refs";}}'
Exists: f
Exists: g
Defined SUB: g <===== No other defined prints worked
Exists: STDOUT
Exists: A
Exists: H
Exists: B
Defined SUB: B <===== No other defined prints worked