mhearse has asked for the wisdom of the Perl Monks concerning the following question:
I'm passing by reference to a subroutine.
field (\@CBR, 3, \@CBRF3, $#CBRF3);
When an error is detected in the subroutine, I want to print out the name of the array being referenced (just the text part of the array name). In this case CBR or CBRF3. Right now when I print the scalar reference, I get a memory address. Is this possible?
Re: printing references
by BrowserUk (Patriarch) on Sep 12, 2003 at 02:11 UTC
|
There isn't a direct, simpe way of retrieving the name of a variable from a reference to it. There is probably a package in the Devel::* group (Padwalker?) that could be used to do this.
There are a couple of ways that you could do this yourself.
- You could build a lookup table of your arrays.
my %lookup;
$lookup{ \@CBR } = 'CBR';
...
sub my_sub{
my( $aref ) = @_;
print "Using: $lookup{ $aref } array\n";
...
}
- Or you could pass the name(s) as additional parameters to the sub
sub my_sub{
my( $aname, $aref, $size, $name, $bref, $size ) = @_;
print "Using $aname and $bname\n";
...
}
- Or you could pass just the names and use eval to obtain the references to the arrays, but this would get messy especially if your sub lives in a different package, or the arrays are lexicals declared a local scope.
Of the three, I think I prefer the second option, but in truth, I think that any is taking a hammer to crack a nut!
Why do you want to do this? If the idea is to log the name of the array in error messages, you should probably be referring to the array by some logical name pertinent to what the sub is doing with the contents of the array rather than the name of a specific instance.
If the idea is to give you an indication of where the sub was called from with bad data, then you should probably look at the caller function which will allow you to access various information about code that called your sub including the file, package, line, subroutine and others. It also has the ability to track back through several levels of caller, and can be used to provide a complete callback trace of the path through the code that was followed.
If your purpose is to provide good information for debugging purposes when your sub gets bad input, then you would probably find the Carp module really useful as it will do all the work of obtaining and formatting the callback trace information for you.
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
If I understand your problem, I can solve it! Of course, the same can be said for you.
| [reply] [d/l] [select] |
Re: printing references
by edoc (Chaplain) on Sep 12, 2003 at 02:04 UTC
|
sub field{
my ($arr1,$num,$arr2,$num2) = @_;
warn "Error in 'arr1'";
# or
warn "Error: first arg to field must be an array reference" unless r
+ef($arr1) eq 'ARRAY';
# etc
}
Unless I've misunderstood your question entirely... without getting into any 'B::' modules which may/may not be able to get you there I don't see how or why you would need this.
Your subroutine takes any args it gets and assigns them to variables of it's choosing.. it's irrelevant what the caller knew them as so you just need to hardcode the name of the array in your subroutine's error message.
cheers,
J | [reply] [d/l] |
Re: printing references
by asarih (Hermit) on Sep 12, 2003 at 02:24 UTC
|
I'm more or less thinking out loud, so I could be off-base here....
Having said that, here's what I think:
when you pass a reference to a subroutine, it doesn't get the name of the referent, but the reference itself. Internally, reference is an RV. RV does not have a field for the name of the referent but only the address.
#!/usr/local/bin/perl -w
use Devel::Peek;
sub func {
$ref = shift;
Dump($ref);
}
@array=('a',5);
func(\@array);
Here's the output:
SV = RV(0x12ebe8) at 0x11df50
REFCNT = 1
FLAGS = (ROK)
RV = 0x122240
SV = PVAV(0x12b4d8) at 0x122240
REFCNT = 3
FLAGS = ()
IV = 0
NV = 0
ARRAY = 0x120950
FILL = 1
MAX = 3
ARYLEN = 0x0
FLAGS = (REAL)
Elt No. 0
SV = PV(0x1134a8) at 0x1131ac
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x112d10 "a"\0
CUR = 1
LEN = 2
Elt No. 1
SV = IV(0x121204) at 0x1132a8
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 5
The important part is the first four lines. It says that what is shifted doesn't remember anything about the referent's name. So unless you pass the referent's name along with the reference itself to the subroutine, you can't do what you want to.
Of course, I'd be happy to be wrong in this case. | [reply] [d/l] [select] |
Re: printing references
by tachyon (Chancellor) on Sep 12, 2003 at 06:09 UTC
|
First point why on earth pass \@CBRF3 and $#CBRF3 to the function why not just get the index of the las element of @CBRF3 in the function. That data seems totally redundent.
Anyway to answer your question the answer is NO as the names of the passed arrays are not remembered by Perl (as shown). You can however get details on the caller, or call stack.
use Carp;
print "Test\n";
func1( @args );
sub func1 { &func2 }
sub func2 {
confess "This is who to blame for sending no args\n" unless @_;
}
__DATA__
This is who to blame for sending no args
main::func2 called at script line 7
main::func1() called at script line 5
I expect knowing where the call(s) came from will be much more useful for debugging than knowing the array names. You can generate this info youself using caller. If you really need them names you will have to pass something like an array of array refs:
func( [ 'ary1' => \@ary1 ], [ 'ary2' => \@ary2 ] );
sub func {
print "Name $_->[0], Array Ref $_->[1]\n" for @_;
}
I suspect you will find the call stack more help.
cheers
tachyon
s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print
| [reply] [d/l] [select] |
Re: printing references
by chromatic (Archbishop) on Sep 12, 2003 at 04:44 UTC
|
eval { field( \@CBR, 3, \@CBRF3, $#CBRF3 ) };
warn "Some error with CBR3: $@\n" if $@;
I'd rarely use this code, as the variable named CBRF3 makes me think you have at least two other arrays named CBRFn. I'd rather have them in a parent array, which would render their names pretty useless.
Still, it seems like a good opportunity to push your error handling code up a level, 'cuz you need it at the caller, not the callee. | [reply] [d/l] [select] |
Re: printing references
by jonadab (Parson) on Sep 12, 2003 at 04:44 UTC
|
When an error is detected in the subroutine, I want to print out the name of the array
Arrays don't have names. All they have is an indexed
list of references to scalar values. Consider the
following case:
field (['foo', 'bar', 'baz'], 3,
[map{somefunc()}@quux], 4);
What 'name' do you propose should be printed?
If you use warn or carp or something along those lines,
you can get Perl to tell you the line number where your
routine was called, and then you can look at that line
in the source and see how it was called (e.g., what
arrays were passed in), but if you want your arrays to
have names then you need something more elaborate than
garden-variety Perl arrays, some kind of object that
knows how to report its name.
$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}}
split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/
| [reply] [d/l] [select] |
|
|