Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

find out method name from the reference

by perlfan99 (Sexton)
on Aug 17, 2008 at 23:02 UTC ( [id://704823]=perlquestion: print w/replies, xml ) Need Help??

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

dear monks,

i have a method takes a function reference as a parameter, is there a way to find out the function name from that references? if that's not possible, is there a way to find out package name of that function?

sub test { my $function_ref = shift; # if ( $function_ref == package1::method1 ) # do something # elsif ( $function_ref == package2::method2) # do something ... } test(\&package1::method1); test(\&package2::method2);

thanks!

Replies are listed 'Best First'.
Re: find out method name from the reference
by betterworld (Curate) on Aug 18, 2008 at 01:38 UTC
    my $ref = \&Pack::foo; # Using B use B; my $gv = B::svref_2object($ref)->GV; print $gv->STASH->NAME, '::', $gv->NAME, "\n"; # Or for simply displaying it in human readable format: use Devel::Peek; Dump $ref;
Re: find out method name from the reference
by syphilis (Archbishop) on Aug 18, 2008 at 01:29 UTC
    Hi,
    Always fun to try to come up with an XSub that does the job. Assuming you're prepared to speculate on what the name is (as in your example), the following works fine for me on perl 5.10:
    use warnings; use strict; use Inline C => <<'EOC'; SV * test (CV * x, char * name) { if(x == get_cv(name, 0)) return newSVuv(1); return newSVuv(0); } EOC package Foo; sub bar {}; package main; my $coderef = \&Foo::bar; my $null; print test($coderef, "Foo::bar"), "\n"; # 1 print test($coderef, "Foo::Bar"), "\n"; # 0 print test($null, "Foo::Bar"), "\n"; # dies appropriately
    I think (untested) that for perl 5.8 you would need to rewrite the XSub as:
    SV * test (SV * x, char * name) { if((CV*)SvRV(x) == get_cv(name, 0)) return newSVuv(1); return newSVuv(0); }
    I don't know about the wisdom of using that approach - and there's quite possibly a better solution anyway.

    It should also be possible to construct an XSub that actually returns the "package::method" name.
    Update: For the package name alone:
    SV * foo1(SV * x) { return newSVpv(HvNAME(CvSTASH((CV*)SvRV(x))), 0); }
    But first make sure it *is* a code reference that you're passing. Better still, just use B; as betterworld suggests.

    Cheers,
    Rob
Re: find out method name from the reference
by GrandFather (Saint) on Aug 18, 2008 at 00:05 UTC

    If you can provide the package name as a parameter then you can:

    use strict; use warnings; package Foo; sub Bar { } package main; sub test { my ($package, $function_ref) = @_; no strict; for my $key (keys %{"${package}::"}) { my $ref = ${"${package}::"}{$key}; if (defined $ref && \&$ref eq $function_ref) { print "${package}::$key\n"; } } } test ('Foo', \&Foo::Bar);

    Prints:

    Foo::Bar

    Perl reduces RSI - it saves typing
Re: find out method name from the reference
by repellent (Priest) on Aug 18, 2008 at 04:37 UTC
Re^2: find out method name from the reference
by Viki@Stag (Sexton) on Aug 18, 2008 at 07:53 UTC
    Instead of using code references the way you mention in your question, you can keep track of the subroutines using a hash like this :
    (You may put this into another package & use it in your script)
    my %code_ref_hash = ( 'method1' => \&Package1::Method1, 'method2' => \&Package2::Method2, );

    So that when you want to call a method, u can just use:
    $code_ref_hash{'method1'}(); # OR $code_ref_hash{'method1'}->();
    Instead of using references, you have the name of the method instead.
    However for this, you have to 'not use strict on refs':
    no strict refs;
Re: find out method name from the reference
by phaylon (Curate) on Aug 19, 2008 at 11:20 UTC

    Could Sub::Identify help?

    From the Synopsis:

    use Sub::Identify ':all'; my $subname = sub_name( $some_coderef );

    Ordinary morality is for ordinary people. -- Aleister Crowley

      Even better.

      The Devel::Peek::CvGV() method is a little vague since the man page mentions that it returns "one of" the globs associated with a subroutine reference. I'm not sure what others might exist, but this would certainly imply that there might be more than one.

      The Sub::Identify module is based on B, which seems like it's a little more appropriate for my use. Plus, it's a little more flexible in exactly what I get back.

      Thanks!

Re: find out method name from the reference
by JavaFan (Canon) on Aug 18, 2008 at 11:40 UTC
    Since it's possible to take references to unnamed functions, or for functions to have more than one name (this is what happens if you import functions), I think the answer is "no".

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (5)
As of 2024-04-19 04:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found