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

How to de-reference a coderef?

by AndyH (Sexton)
on Dec 09, 2004 at 14:52 UTC ( [id://413556]=perlquestion: print w/replies, xml ) Need Help??

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

Update:

As usual, my attempts to keep a question short introduced confusion rather than clarity. So, I should explain more clearly what I am trying to do.

I have a complex data structure, a hash of hashes and arrays, that describes a set of menus for a CGI application. For each menu item, there is the text of the menu, the link text, the user documentation and the reference to the subroutine to be run when the menu entry is chosen.

A "parser" generates the appropriate menus and also handles when a menu item is chosen, as this might be a subroutine, another menu or a different URL entirely. If a subref entry exists in the hash, it calls the subroutine. WHat I needed was for the parser code to be able to get at the name of the subroutine before calling it, to allow for debug, context-sensitive help etc.

As usual, also, the superb perlmonks response produced not only rapid way of doing what I needed to do but also a thoguth-provoking discussion on other ways of doing it, doing the whole thing differently, and the meaning of perl life. Thanks to the monks.

AndyH

Replies are listed 'Best First'.
Re: How to de-reference a coderef? (B tricks)
by ysth (Canon) on Dec 10, 2004 at 10:35 UTC
    Unlike e.g. array refs, every code ref has a backreference to its glob (so that when you call it, caller can know the sub name). This is fairly easily accessible with the B module (which provides introspection facilities for perl thingies):
    use B; sub coderef2name { eval { my $obj = B::svref_2object( shift() ); $obj->GV->STASH->NAME . "::" . $obj->GV->NAME; } || undef; }
    Returns something like pkgname::__ANON__ for anonymous subs, or undef if something goes wrong (like being passed an array ref instead of a code ref).

    Updated to use GV->STASH->NAME, not STASH->NAME. Thanks, betterworld

      How do you do this in XS? Given a CV how do you get the name for the corresponding named sub?
        use strict; use warnings; use feature qw( say ); use Inline C => <<'__EOI__'; SV* coderef2name(CV* cv) { const GV * const gv = CvGV(cv); const HV * const stash = GvSTASH(gv); const char * const pkg_name = HvNAME(stash); const char * const func_name = GvNAME(gv); SV * const fqn = newSVpvn("", 0); sv_catpv(fqn, pkg_name); sv_catpv(fqn, "::"); sv_catpv(fqn, func_name); return fqn; // Mortalised by Inline } __EOI__ sub f {} say coderef2name(\&f);
        You call coderef2name from XS, that is how you do it
Re: How to de-reference a coderef?
by duff (Parson) on Dec 09, 2004 at 14:55 UTC

    You typically don't need the name of the subroutine. The subroutine may not even have a name if it's anonymous. If you have the reference, just use $code_ref->(@args) to execute it or &{$code_ref}(@args).

Re: How to de-reference a coderef?
by mpeters (Chaplain) on Dec 09, 2004 at 14:58 UTC
    Dereferencing and getting the name of the referenced object are two different things. If I had a reference to an array there is no way to find out what the name of that array is so why would there be a way to do it with subroutines/coderefs?

      Oh there *is* a way, but it's not big and it's not clever and won't work with anonymous subs, but you can do it if you really, really, really must:

      + sub foo { } + my $bar = \&foo; + foreach my $foo ( keys %:: ) { my $zub = \&{$::{$foo}}; if ( $bar eq $zub ) { print $foo,"\n"; last; } }
      See I told you it wasn't big or clever ....

      /J\

        What about other namespaces? What about multiple matches? A sub is a little like an inode on a unix filesystem: it may have several names, or none; and several handles, or none.

        It may not be big but it certainly is clever!

        To those kind people who pointed out that:
        (a)I could execute the sub without knowing its name - I knew that
        (b)That it might not have a name - in my case I knew it had a name but not what the name was.

        My problem was that the coderef was being passed in from somewhere else but I needed to get at the subroutine name, not to execute it but to print for debug, logging, etc.

        As usual, perlmonks has excelled itself for speed and quality of response ...

        Thanks

Re: How to de-reference a coderef?
by Anonymous Monk on Dec 09, 2004 at 15:09 UTC
    No, if only for the fact it doesn't have to have a name:
    my $code_ref = sub {print "Hello, $_[0]\n"};
    Or it might have multiple names. foo_bar might have been imported from another package (or exported to another one).

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (8)
As of 2024-04-16 10:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found