Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Access variable names

by andreas1234567 (Vicar)
on Sep 01, 2005 at 07:18 UTC ( [id://488315]=perlquestion: print w/replies, xml ) Need Help??

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

Hi,

I often find myself having to check a long list of variables for defined- and non-zero-ness. For debugging purposes it would have been helpful to print the name of the variable that were undef or empty.

#!/usr/bin/perl use strict; use warnings; ####################################################### # Input: list of scalars. # Return: 1 if all scalars are defined and non-empty, # otherwise undef. sub defnz { ####################################################### for my $item (@_) { if (!defined($item)) { print STDERR "not defined\n"; return; } elsif ($item eq '') { print STDERR "empty\n"; return; } } print STDOUT "All scalars defined and non-empty\n"; return 1; # all items in list defined and non-empty } my ($foo,$bar,$baz) = ("FOO","BAR","BAZ"); defnz($foo,$bar,$baz); ($foo,$bar,$baz) = ("FOO","BAR",""); defnz($foo,$bar,$baz); ($foo,$bar,$baz) = ("FOO",undef,""); defnz($foo,$bar,$baz); __END__
Above sample code outputs:
All scalars defined and non-empty empty not defined
I would want it to output:
All scalars defined and non-empty '$baz' empty '$bar' not defined
Is there a way to access variable names like this?

Best regards,
Andreas
--

Replies are listed 'Best First'.
Re: Access variable names
by Roger (Parson) on Sep 01, 2005 at 08:07 UTC
    It is not possible to know the variable name of the variable passed into the subroutine, you need to tell it the name of the varaibles.

    Just a minor modification to your code will make it work - just pass in the variable name in csv format.
    #!/usr/bin/perl use strict; use warnings; sub defnz { my @names = split /,/, shift; my %vars; @vars{@names} = @_; for my $item (@names) { if (!defined($vars{$item})) { print STDERR "$item is not defined\n"; return; } elsif ($vars{$item} eq '') { print STDERR "$item is empty\n"; return; } } print STDOUT "All scalars defined and non-empty\n"; return 1; # all items in list defined and non-empty } my ($foo,$bar,$baz) = ("FOO","BAR","BAZ"); defnz('$foo,$bar,$baz', $foo,$bar,$baz); ($foo,$bar,$baz) = ("FOO","BAR",""); defnz('$foo,$bar,$baz', $foo,$bar,$baz); ($foo,$bar,$baz) = ("FOO",undef,""); defnz('$foo,$bar,$baz', $foo,$bar,$baz); __END__ output is: All scalars defined and non-empty $baz is empty $bar is not defined
    Simpler still, you can use Data::Dumper to inspect the variables.
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; sub defnz { my @names = split /,/, shift; my %vars; @vars{@names} = @_; for my $item (@names) { if (!defined($vars{$item}) || $vars{$item} eq '') { print STDERR Dumper(\%vars); return; } } print STDOUT "All scalars defined and non-empty\n"; return 1; # all items in list defined and non-empty } my ($foo,$bar,$baz) = ("FOO","BAR","BAZ"); defnz('$foo,$bar,$baz', $foo,$bar,$baz); ($foo,$bar,$baz) = ("FOO","BAR",""); defnz('$foo,$bar,$baz', $foo,$bar,$baz); ($foo,$bar,$baz) = ("FOO",undef,""); defnz('$foo,$bar,$baz', $foo,$bar,$baz); __END__ output: All scalars defined and non-empty $VAR1 = { '$foo' => 'FOO', '$baz' => '', '$bar' => 'BAR' }; $VAR1 = { '$foo' => 'FOO', '$baz' => '', '$bar' => undef };

      It is not possible to know the variable name of the variable passed into the subroutine ...

      With Perl out of the box, that's true. Otherwise, use PadWalker.

      Cheers,
      Ovid

      New address of my CGI Course.

Re: Access variable names
by sk (Curate) on Sep 01, 2005 at 07:30 UTC
    There might be better ways to do this. Here is one way (not very clean tho)

    use strict; use warnings; my $x = 10; my $y = undef; my $check = '$x,$y'; my @vars = split /,/,$check; for (@vars) { if (defined(eval($_))) { print "$_ = Defined\n"; } else { print "$_ = Not defined\n";} } __END__ $x = Defined $y = Not defined

    There are risks associated with eval so you need to watch out

    cheers

    SK

      Thanks! That was a cool solution. One caveat though, the variables to be checked must be visible (scope-wise) to the eval:
      use strict; use warnings; my $foo = "1"; my $bar = "42"; my $defnz = sub { for (@_) { if (!defined(eval($_))) { print "$_ undef!"; return; } elsif (eval($_) eq '') { print STDERR "$_ empty!"; return; } } return 1; }; my $baz = "101"; print "ok1\n" if &$defnz(split /,/,q($foo,$bar)); print "ok2\n" if &$defnz(split /,/,q($foo,$bar,$baz)); __END__ ok1 $baz undef!
Re: Access variable names
by gargle (Chaplain) on Sep 01, 2005 at 11:34 UTC

    Something silly...

    You can use tie to follow your variable use during the run of your program.

    Keep in mind that you can't directly access the name of the variable yourself, you have to pass the name as a parameter to your bound object.

    The code would go like this:

    Package Defined (Defined.PM)
    package Defined; use strict; use warnings; sub TIESCALAR { my $class = shift; my $name = shift; my $self = { 'NAME' => $name, 'DEFINED' => undef, }; return bless ($self, $class); } sub FETCH { my $self = shift; my $name = $self->{'NAME'}; my @caller = caller; if (defined $self->{'DEFINED'}) { print STDERR "@caller -> $name defined\n"; } else { print STDERR "@caller -> $name undefined\n"; } } sub STORE { my $self = shift; my $value = shift; my $name = $self->{'NAME'}; my @caller = caller; $self->{'DEFINED'} = $value; print STDERR "@caller -> $name defined with value $value\n"; } 1;
    The caller (test.pl)
    #!/usr/bin/perl use Defined; use strict; use warnings; my $var; tie $var, 'Defined', '$var'; print $var; $var = 1; print $var; $var = 5
    Output
    bash-3.00$ ./test.pl main ./test.pl 11 -> $var undefined main ./test.pl 12 -> $var defined with value 1 main ./test.pl 13 -> $var defined main ./test.pl 14 -> $var defined with value 5

    As I said, a bit silly. However, it might helpt in some cases of debugging.

    --
    if ( 1 ) { $postman->ring() for (1..2); }
Re: Access variable names
by traveler (Parson) on Sep 01, 2005 at 15:17 UTC
    Tools like uninit can help with the uninitialized issue. You also might look at Tie::Watch or B::Lexinfo for techniques on how to find variables in the padlist.

    HTH, --traveler

Re: Access variable names
by Akhasha (Scribe) on Sep 01, 2005 at 21:24 UTC
    There is also Ovid's own Data::Dumper::Simple, implemented using a source filter, though he probably opted to mention PadWalker instead for a good reason.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://488315]
Approved by sk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (3)
As of 2024-04-19 05:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found