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

Re: How to get function's name inside of CODE attribute

by juster (Friar)
on Oct 06, 2011 at 14:59 UTC ( #929999=note: print w/replies, xml ) Need Help??

in reply to How to get function's name inside of CODE attribute

I ran into this before (in perl 5.10) when messing around with attributes. The cause of your problems is that perl attributes are evaluated at compile time, before the subs are evaluated.

Let me back up a bit. Attribute::Handlers is a wrapper around the simpler attribute handling logic in perl. This simpler attribute handling is described in the attributes module. When an attribute is used, perl calls the MODIFY_type_ATTRIBUTE method on the package who owns the sub or variable. In your case type is "CODE". The arguments passed to this method are the package name, coderef, and the attribute text (without the colon). The coderef is a placeholder that is later filled in after perl finishes compiling the sub. Until then, it is empty... ish.

The only way I could think to do get the names would be to save the coderefs for examining later, when all the information is available. Then you can dissect them to get the information you want.

use warnings; use strict; package FooAttr; use Devel::Peek qw(Dump); use B qw(); our @Subs; sub MODIFY_CODE_ATTRIBUTES { my ($pkg, $cref, @attrs) = @_; # Sucks in perl 5.10. Dump($cref); my @bad; for my $attr (@attrs){ if ($attr eq 'FOO') { push @Subs, $cref; } else { push @bad, $attr; } } return @bad; } # Add "FooAttr" to @UNIVERSAL::ISA at *compile-time*. # Otherwise Bar won't find MODIFY_CODE_ATTRIBUTES. BEGIN { push @UNIVERSAL::ISA, __PACKAGE__; } package Bar; use Devel::Peek qw(Dump); # This calls FooAttr::MODIFY_CODE_ATTRIBUTES at *compile-time*. sub baz :FOO {} # Keep in mind this is at runtime. Let's examine the same coderefs! for my $cr (@FooAttr::Subs) { Dump($cr); # This is what Sub::Identify[/Information] does but it # can also use C code to avoid the B module. my $gv = B::svref_2object($cr)->GV; printf "%s::%s\n", $gv->STASH->NAME, $gv->NAME; }

There are zeroes at the top of the output where Devel::Peek's Dump is called by MODIFY_CODE_ATTRIBUTE and the filled in values at the bottom of the output are printed by the runtime code at the end of the Bar module. Keep in mind these are for the same code reference.

Attribute::Handlers (which also adds to @UNIVERSAL::ISA) tries to convert the provided coderef to a symbol by examining all the symbols in the $pkg that is passed to MODIFY_CODE_ATTRIBUTES to see if they equal the coderef. This fails because the symbols are not yet populated in the package's symbol table. Again, this is because weird things are going on at compile-time, that I don't fully understand.

Replies are listed 'Best First'.
Re^2: How to get function's name inside of CODE attribute
by menth0l (Monk) on Oct 07, 2011 at 07:14 UTC
    This is very interesting but it seems it's an overkill for what i need.
    I think i'll just cut corners and add a new parameter to attribute with function name/path, i.e.:
    package FOO; sub foo :BAR (func => 'FOO::foo') { ... }

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://929999]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (11)
As of 2017-06-23 09:32 GMT
Find Nodes?
    Voting Booth?
    How many monitors do you use while coding?

    Results (539 votes). Check out past polls.