http://www.perlmonks.org?node_id=953831

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

Hi

I'm trying to inspect the symbols of a package and filter which arrays, hashes, scalars and subs where used.

This works pretty fine for all slots of a glob but for scalars!

Normally unused slots are undef or hold a reference to the corresponding type. (see ARRAYs)

But unused scalar slots automatically hold \undef which is not distinguishable from using them and setting them to undef.

DB<191> *PCKG::unknown{ARRAY} => undef DB<192> @PCKG::foo=(1,2,3) => (1, 2, 3) DB<193> *PCKG::foo{ARRAY} => [1, 2, 3] DB<194> *PCKG::foo{SCALAR} # why \undef and not undef ??? => \undef DB<195> $PCKG::foo=undef => undef DB<196> *PCKG::foo{SCALAR} # same effect => \undef DB<198> undef $PCKG::foo => undef DB<199> *PCKG::foo{SCALAR} # again => \undef

Any idea how to solve this?

Cheers Rolf

Replies are listed 'Best First'.
Re: Problem to inspect scalars in STASH
by educated_foo (Vicar) on Feb 15, 2012 at 05:08 UTC
    Yes, this is annoying, and even more so when defined(@array) and defined(%hash) become deprecated. The solution I came up with is to use defined($$name) for scalars, and defined(*{$name}{THING}) for the others. I think it works on all current Perls without polluting the stash, e.g.
    main @> $Test::x = 1; @Test::y = qw(2 3); %Test::z = (a => 'b'); main @> keys %Test:: y x z main @> join ' ', "SCALARS:", grep defined(${"Test::$_"}), keys %Test: +: 'SCALARS: x' main @> join ' ', "ARRAYS:", grep defined(*{"Test::$_"}{ARRAY}), keys +%Test:: 'ARRAYS: y' main @> join ' ', "HASHES:", grep defined(*{"Test::$_"}{HASH}), keys % +Test:: 'HASHES: z' main @> join ' ', "SCALARS:", grep defined(${"Test::$_"}), keys %Test: +: 'SCALARS: x'
      Thanks for your help... :)

      > The solution I came up with is to use defined($$name) for scalars,

      Sorry, that's not a solution because it excludes all declared package variables which became undef in the meantime.

      Think of something like  $flag = () in the middle of the code. I'm trying to fix the tab-expansion in the perldebugger, actually $f#TAB# lists all symbols starting with f, no matter which slot is used.

      DB<223> sub flo {} => 0 DB<224> $f # type TAB $f $find $flag $flo

      As a workaround I could include all symbols where only the scalar slot is defined, but if someone decides to have equally named sub &flo AND scalar $flo where the latter is undef, I can't tell if the scalar belongs to the code or not.

      While this cases seems rare enough - most people tend to use different names for different sigils - it's not a 100% solution.

      If there is no better suggestion, I will need to parse the code to reliably find all scalars.

      >Yes, this is annoying,

      FWIW I consider this behavior a bug.

      Cheers Rolf

        You're right, of course, and I agree that the SCALAR auto-vivification thing is a bug. I remember discussing this with some P5P folks awhile back, and IIRC this auto-creation of the SCALAR slot was fairly well-baked into the core. Still, you think that wandering through the symbol table should be easy -- it's just a hash of GLOBs, right? -- and then you run into all this stuff. *sigh*
Re: Problem to inspect scalars in STASH
by ikegami (Patriarch) on Feb 15, 2012 at 04:38 UTC
    There's no problem. Those globs indeed have a populated scalar slot.