Get variable from its name string or vice versa?

J

Jerry Krinock

I have written a function to log variables like this:

" varName: varValue"

but it takes two arguments: the variable name as a string, and the
variable symbol:

logVar ("myVar", $myVar) ;

sub logVar {
my $varName = shift ;
my $varValue = shift ;
if (!defined($varValue)) {
$varValue = "<undef>" ;
}
printf ("%16s: %s\n", $varName, $varValue) ;
}

Is there any way to get "myVar" from $myVar or vice versa, without
foregoing 'strict' and 'warnings'?

Note: My actual code uses Std::Log but the problem is the same.

Thanks,

Jerry Krinock
 
J

Jens Thoms Toerring

A. Sinan Unur said:
(e-mail address removed):
This is a FAQ:
perldoc -q "How can I use a variable as a variable name"

I think the OP is looking for something a bit different, i.e.
a way to get the name of variable from the variable itself.
I.e. some hypothetical code like

my $x = 10;
logvar( \$x );

sub logvar {
my $varref;
print get_name_from_reference( $var ) . " " . $$var . "\n";
}

It's clear that for something like this to work a reference to
the variable has to be passed to the function. But I have no
idea how to write a function like get_name_from_reference()
and also have my doubts that it is possible at all (but then
this is Perl and there's so much magic that it is hard to be
sure;-)
Regards, Jens
 
A

advice please wireless 802.11 on RH8

I have written a function to log variables like this:

" varName: varValue"

but it takes two arguments: the variable name as a string, and the
variable symbol:

logVar ("myVar", $myVar) ;

sub logVar {
my $varName = shift ;
my $varValue = shift ;
if (!defined($varValue)) {
$varValue = "<undef>" ;
}
printf ("%16s: %s\n", $varName, $varValue) ;

}

Is there any way to get "myVar" from $myVar or vice versa, without
foregoing 'strict' and 'warnings'?

Note: My actual code uses Std::Log but the problem is the same.

Thanks,

Jerry Krinock

sounds like you need the (non-existent) Perl func uneval()
 
B

Ben Morrow

Quoth Jerry Krinock said:
I have written a function to log variables like this:

" varName: varValue"

but it takes two arguments: the variable name as a string, and the
variable symbol:

logVar ("myVar", $myVar) ;

sub logVar {
my $varName = shift ;
my $varValue = shift ;
if (!defined($varValue)) {
$varValue = "<undef>" ;
}
printf ("%16s: %s\n", $varName, $varValue) ;
}

Is there any way to get "myVar" from $myVar or vice versa, without
foregoing 'strict' and 'warnings'?

You can do this with PadWalker. If you need more hints than that, you
probably shouldn't be trying... :)

Ben
 
J

jerrykrinock

I think the OP is looking for something a bit different...

Yes, I am.

This is a FAQ:

perldoc -q "How can I use a variable as a variable name"

I'd read that, and now studied it further, but I get the impression
that the only solution is to always define all of my variables in my
own hash, just in case I ever decided that I wanted to log one of
them.

That's not going to be any fun, and not very readable by earthlings.
Indeed, this code works:

#!/usr/bin/perl
use strict ;
use warnings ;

my %MY_VARS ;

# New Way to declare a Loggable Variable...
# Instead of just "my $fred",
# I now have to write:
my $fred = $MY_VARS{"fred"} ;

# New Way to assign a Loggable Variable
# Instead of just "$fred = 23",
# I now have to write:
$MY_VARS{"fred"} = 23 ;

# Well, after all that yuck, indeed, as desired,
# I can log it with only one argument, :

logVar("fred") ;

# Using this handy function
sub logVar {
my $varName = shift ;
my $varValue = $MY_VARS{$varName} ;
if (!defined($varValue)) {
$varValue = "<undef>" ;
}
printf ("%32s: %s\n", $varName, $varValue) ;
}

But it's hardly worth all that massive obfuscation. Can someone
confirm that there is indeed no way to simply log a "regular" variable
and its name without having to type both of them, or is Jens correct
that it can't be done?

Jerry
 
N

nolo contendere

This is a FAQ:

perldoc -q "How can I use a variable as a variable name"

I don't think this is quite it...perhaps the Debugger's DumpPackages?
This displays the symbol tables of packages.
 
J

jerrykrinock

You can do this with PadWalker.

Thank you. I haven't tried it yet, but documentation of PadWalker
from CPAN declares a var_name() function that seems to be exactly what
I want.

Apparently this was a tricky feat. From the documentation: "I
wouldn't recommend using PadWalker directly in production code, but
it's your call. Some of the modules that use PadWalker internally are
certainly safe for and useful in production."

And from a review: "PadWalker is really, really useful if you need to
debug something really, really weird. I hope you never have to use
this module, but if you do, use it boldly."

:-|

Thanks for all the help. I'll probably give PadWalker a try next time
I am feeling bold, and have a little time to spare before production.

Jerry Krinock
 
U

Uri Guttman

j> Thank you. I haven't tried it yet, but documentation of PadWalker
j> from CPAN declares a var_name() function that seems to be exactly what
j> I want.

j> Apparently this was a tricky feat. From the documentation: "I
j> wouldn't recommend using PadWalker directly in production code, but
j> it's your call. Some of the modules that use PadWalker internally are
j> certainly safe for and useful in production."

j> And from a review: "PadWalker is really, really useful if you need to
j> debug something really, really weird. I hope you never have to use
j> this module, but if you do, use it boldly."

j> :-|

j> Thanks for all the help. I'll probably give PadWalker a try next time
j> I am feeling bold, and have a little time to spare before production.

and i doubt you have a legit reason to need this in production code. i
smell an XY problem here. when someone needs to use such a dark magic
solution, i say the problem is poorly specified or similar. tell us what
the real problem is, don't ask how to do something requiring magic. i
can find no good reason (other than debugging or wacko stuff) for
needing the name of a variable. and if you have anon references, you
can't get any name.

uri
 
E

Eric Pozharski

Thanks for all the help. I'll probably give PadWalker a try next time
I am feeling bold, and have a little time to spare before production.

(say that I'm wrong) Did you give up on debuger?
 
P

Peter J. Holzer

I think the OP is looking for something a bit different, i.e.
a way to get the name of variable from the variable itself.
I.e. some hypothetical code like

my $x = 10;
logvar( \$x );

sub logvar {
my $varref;
print get_name_from_reference( $var ) . " " . $$var . "\n";
}

I think what is needed in this case a macro, not a subroutine. You want
to turn

logvar( $x );

into

print '$x' . " " . $x . "\n";

and similarly

logvar( $foo->{bar}{$y} );

into

print '$foo->{bar}{$y}' . " " . $foo->{bar}{$y} . "\n";

Macros are not part of perl per se, but can be implemented via source
filters. It shouldn't be too hard to write a filter like that.

But it happens that Damian Conway already wrote one which might do what
the OP wants: Smart::Comments.

#!/usr/local/bin/perl5.10.0
use warnings;
use strict;
use Smart::Comments;


my $var = 5;
### At <where> ...
### $var
### At <where> ...: $var
__END__

prints:

### At "./foo", line 8 ...
### $var: 5
### At "./foo", line 10 ...: 5

hp
 
J

jerrykrinock

I think what is needed in this case a macro, not a subroutine...
Macros are not part of perl per se, but can be implemented via source
filters. It shouldn't be too hard to write a filter like that.
Thank you, Peter. Indeed I do want a preprocessor macro, but I was
not aware that perl's preprocessor macros were called filters
(perlfilter).
But it happens that Damian Conway already wrote one which might do what
the OP wants: Smart::Comments.

Well, I want something which will log to the same file as Log::StdLog
does, so I wrote my own. It's got some rough edges and a kludge or
two, but it works and does not use any of the black magic. Here it
is. Thanks again for the help...

package LogVar ;

use Filter::Util::Call;

sub import {
my ($type) = @_;
my ($ref) = [];
filter_add(bless $ref);
}

sub filter {
my ($self) = @_;
my ($status);
if (($status = filter_read()) > 0) {
# Substitute for the one-argument version, LogVar(varName)
s /LogVar[\s]*\([\s]*(\$|\@|\%)([\w]+)[\s]*\)/doLogVar($2,
$1$2, info)/ ;

# Substitute for the two-argument version, LogVar(varName,
level),
# when the level is 'warn'.
# The 'warn' has to be treated specially because 'warn' is
# also a predefined function in perl and really weird things
# happen if I don't do this
s /LogVar[\s]*\([\s]*(\$|\@|\%)([\w]+),[\s]*warn[\s]*\)/
doLogVarWarn($2, $1$2)/ ;

# Substitute for the two-argument version, LogVar(varName,
level)
# for other levels
s /LogVar[\s]*\([\s]*(\$|\@|\%)([\w]+),[\s]*([\w]+)[\s]*\)/
doLogVar($2, $1$2, $3)/ ;

# Now, heres the tricky part. I need to define the functions
# doLogVar, doLogVarWarn (and makeDefined, which they call).
# For some reasons which I don't understand,
# (1) If I simply define sub doLogVar in this module, it is
# "not found" when it runs from the host program file.
# (2) If I change the calls to "LogVar::doLogVar", then it
runs,
# but nothing gets logged
# So, my workaround for these two problems is to add the
placeholder
# use logVarFunctions
# to the main program file and then replace it with the
function
# definitions using the following s///, except s''' is used
to
# avoid variable interpolations.
# This also has the advantage of using the same Log::StdLog
# initialization and thus the same level that is used in the
main
# program file.
s 'use[\s]*LogVarFunctions[\s]*;'
sub makeDefined {
my $var_ref = shift ;
if (!defined($$var_ref)) {
$$var_ref = "<undefined>" ;
}
}

sub doLogVar {
my $varName = shift ;
my $varValue = shift ;
my $level = shift ;
makeDefined(\$varValue) ;
my $msg = sprintf ("%24s: %s\n", $varName, $varValue) ;
print {*STDLOG} $level => $msg ;
}

sub doLogVarWarn {
my $varName = shift ;
my $varValue = shift ;
makeDefined(\$varValue) ;
my $msg = sprintf ("%24s: %s\n", $varName, $varValue) ;
print {*STDLOG} \'warn\' => $msg ;
}
'

}
$status;
}


1;

__END__

=head1 NAME

LogVar - Logs variable name and value using Log::StdLog

=head1 SYNOPSIS

# Your program file must be using Log::StdLog and
# have initialized it with a level.

# Both of these are necessary
use LogVar ;
use LogVarFunctions ;

my $myVar = 5 ;

# Log to Log::StdLog at default level 'info'
LogVar($myVar) ;

# Log to Log::StdLog at some other level
LogVar($myVar, trace) ;
LogVar($myVar, debug) ;
# ...
LogVar($myVar, none) ;


=head1 DESCRIPTION

This module provides a perl filter (see perlfilter), which is a
preprocessor.
It provides the macro LogVar() which extracts the variable name from
the
first argument and logs the variable name and value to the file
designated
in Log::StdLog, producing lines that are nicely aligned like this:

$myVar: 5
$name: Jerry
$weight: 150.3
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top