Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

printing references

by mhearse (Chaplain)
on Sep 12, 2003 at 01:13 UTC ( [id://290888]=perlquestion: print w/replies, xml ) Need Help??

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?

Replies are listed 'Best First'.
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.

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

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.

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

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.

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$/

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (1)
As of 2024-04-24 14:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found