Given
# package main;
our $f;
sub f{}
sub g {}
1;
How can I determine that $f
, but not $g
, has been declared? Off the cuff, I'd thought that *{main::g}{SCALAR}
might be undefined, but it is a bona fide SCALAR ref.
Background: I'd like to import a variable into main::
, but carp or croak if that variable is already declared.
EDIT Added an f
subroutine in response to @DVK's initial answer.
ANSWER (2010-07-27)
This isn't easy, but it is possible.
An eval
technique is most portable, working on perls older than 5.10. In more recent perls, introspective modules like Devel::Peek
and B
can discriminate.
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
Older perls (pre-5.10) will always have something in the scalar slot.
On newer perls, it appears that the old behavior is mimicked when you try to do *FOO{SCALAR}.
You can use the B introspection module to check the scalar slot, though:
# package main;
our $f;
sub f {}
sub g {}
use B;
use 5.010;
if ( ${ B::svref_2object(\*f)->SV } ) {
say "f: Thar be a scalar tharrr!";
}
if ( ${ B::svref_2object(\*g)->SV } ) {
say "g: Thar be a scalar tharrr!";
}
1;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With