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

Dear Monks,

even though I cannot imagine this has never been asked before and I am almost sure it isn't possible what I am trying to do, I thought I might as well ask the question. If the answer's a no then at least I'll be able to sleep easy knowing that it wasn't my failing :-)

Imagine a situation where a scalar var, let's call it $coderef, gets assigned a reference to a named subroutine, which for the sake of tradition I shall call &foo. Is there any way whatsoever, at runtime, to get perl to cough up the name of the subroutine a coderef is pointing to? In other words, a way of making perl return the value &foo as the subroutine $coderef points to, as opposed to CODE(memory_address)? And, assuming this is even possible, what would be the result if the subroutine is anonymous?

A great many thanks in advance once again.

Update for clarity with a code example:

package thingy; use strict; use warnings; sub new { my($class, $name, $coderef, @args) = @_; #insert checking for proper values here, removed for readability's s +ake my $self = {}; bless($class, $self); $self->{'Coderef'} = $coderef; $self->{'Args'} = \@args; return $self; } sub execute { my $self = shift; $self->{'Coderef'}(@{$self->{'Args'}}); } sub details { my $self = shift; print "executes coderef *insert black magic here* with arguments " . + join(' ', @{$self->{'Args'}}) . "\n"; }
Remember rule one...

Replies are listed 'Best First'.
Re: Finding the name of the target of a coderef
by Tanktalus (Canon) on Apr 14, 2005 at 23:37 UTC

    You mean something like this? (Super search terms: "search name code ref")

      Oooooooh, great find, didn't run across that one myself. Looks like B includes all sorts of funky black magic for me to play with :-)

      Remember rule one...
Re: Finding the name of the target of a coderef
by Errto (Vicar) on Apr 15, 2005 at 00:48 UTC
    Just an observation:
    sub bar { print +(caller 0)[3]; } sub foo { bar } my $baz = \&foo; $baz->(); __END__ main::foo
    Until I tried it I didn't think it would work. I guess this works for the same reason the B trick works: that the system knows that a certain subroutine has a name, even when you call it through a reference.
Re: Finding the name of the target of a coderef
by gam3 (Curate) on Apr 14, 2005 at 23:22 UTC
    I think that this is what you want.
    sub bob { print 'bob'; } my $match = \&bob; my $nomatch = sub { print 'nob'; }; *alias = \&bob; for my $key (keys %main::) { if ($match == \&{$key}) { print "matched to $key\n"; } if ($nomatch == \&{$key}) { print "matched to $key\n"; } }
    This will match `bob' and nothing else.

    This will only find subroutines in the main package.

    Update: Added Alias for completness.

    -- gam3
    A picture is worth a thousand words, but takes 200K.
      Good start, now recurse down the entire symbol table, and you've got something that's a bit more useful.

      Oh, and it would return a list of many things that point to the that coderef.
Re: Finding the name of the target of a coderef
by bschmer (Friar) on Apr 14, 2005 at 23:32 UTC
    How about:
    #!/usr/bin/perl sub foo { print "In foo\n"; } sub findit { my $ref = shift; local(*alias); *stash = *{"main::"}; while ((my $varname, my $globvalue) = each %stash){ next if $varname eq "alias"; *alias = $globvalue; if (defined(&alias)){ if ($ref eq \&alias){ return $varname; } } } } my $fref = \&foo; my $fname = findit($fref); print "ref points to $fname\n";
    bryan@web ~$ ./ns
    ref points to foo
    bryan@web ~$
    
Re: Finding the name of the target of a coderef
by brian_d_foy (Abbot) on Apr 15, 2005 at 04:37 UTC
Re: Finding the name of the target of a coderef
by revdiablo (Prior) on Apr 14, 2005 at 23:04 UTC

    This question gets asked from time to time. The usual answer is, why do you want to do that? It is a strange thing to want, and when you consider that something may be called by many names, or even no name at all, it is nearly pointless as well.

      The main reason I want to do this is because I'm working on a small script that executes a certain subroutine with certain arguments after x amount of time, a timed event so to say. In order to facilitate ease of use I was hoping to find a way to provide a list of all timed events currently in the queue, with the subroutines they're pointing to, the arguments and the amount of time left till execution.

      Remember rule one...

        I would solve that by passing a label along with the coderef when I added the timed event to the queue. Something along the lines of:

        add_to_queue(foo => \&foo, [ @fooargs ], $footime); add_to_queue(bar => \&bar, [ @barargs ], $bartime); dump_queue(); { my @queue; sub add_to_queue { my ($label, $code, $args, $time) = @_; push @queue, [ $label, $code, $args, $time ]; } sub dump_queue { for (@queue) { my ($label, $code, $args, $time) = @$_; print "Will execute $label with @$args at $time\n"; } } }

        Of course, your exact calling conventions will likely be different, but this is just to give you the general idea.

Re: Finding the name of the target of a coderef
by jbrugger (Parson) on Apr 14, 2005 at 22:34 UTC
    You mean something like this?
    #!/usr/bin/perl use strict; use warnings; my $anon = sub { return "foo " . "bar" }; my $retVal = &$anon; print $retVal ;

    update
    Ah i did not understand the question that way. After rereading i even thought more like the following, where you can get the sub (a) since it's the key of a blessed hash, with the sub inside...
    well, now i have to think about it...
    #!/usr/bin/perl use strict; use warnings; my $anon = bar->new; my $retVal = &{$anon->{a}}; print $retVal ; package bar; sub new{ my $self = bless{}; $self->{a} = sub { return "bar"; } ; $self; }
    "We all agree on the necessity of compromise. We just can't agree on when it's necessary to compromise." - Larry Wall.
      I think the OP was more interested in this:
      sub foo { # do groovy things here } my $coderef = \&foo; my $method_name = mythical_coderef_name_fetcher($coderef); print $method_name; # output is 'foo'
      AFAIK there's no way to do this. Any takers?
      code example moved to original post for ease of reading.
Re: Finding the name of the target of a coderef
by kwaping (Priest) on Apr 14, 2005 at 22:52 UTC
    This may seem simplistic, but if the sub normally takes arguments, you could just:
    return '&foo' unless shift;
    Or something similar. Then just dereference the reference and run the sub without arguments.