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

I originally posted this as a follow-up to the named anonymous subs thread, but a monk of greater standing than I suggested that I might generate a little more heat if I started a new thread here. So...

As maintainer of Class::MethodMaker, I have more than a passing interest in this technique: C::MM generates anonymous routines by the bucket-load, and as well as debugging, I'm particularly interested in profiling, too.

I'd been meaning to do something about this for a couple of years now, and this thread finally galvanized me into action. After two days of tinkering with it, and several false starts, I've finally come up with this XS incantation:

void set_sub_name(SV *sub, char *pname, char *subname, char *stashname) CODE: CvGV((GV*)SvRV(sub)) = gv_fetchpv(stashname, TRUE, SVt_PV); GvSTASH(CvGV((GV*)SvRV(sub))) = gv_stashpv(pname, 1); GvNAME(CvGV((GV*)SvRV(sub))) = savepv(subname); GvNAMELEN(CvGV((GV*)SvRV(sub))) = strlen(subname);

The pname is the package name, the subname the subname, and stashname is the name of a stash to generate to attach the code to, to avoid overwriting the original stash (which is the package the code was compiled in), or the ANON entry in the pname stash. The above certainly appears to work, both with stack traces & the profiler, and doesn't break my code. I was concerned that generating a new stash for each subr might hurt the memory consumption, but empirical testing suggests that the effect is minimal-to-nil.

I'm no XS programmer, so I'd appreciate any constructive feedback anyone has.

Replies are listed 'Best First'.
Re: Naming Anonymous Subs
by ikegami (Patriarch) on Oct 20, 2004 at 21:20 UTC
    A monk recently uploaded Sub::Name to CPAN, which does something similiar. You may want to take a peek at how he does it.
Re: Naming Anonymous Subs
by Elian (Parson) on Oct 20, 2004 at 21:33 UTC
    Any reason to not just shove the anonymous sub reference into the appropriate slot in the glob in the global namespace? Not that I'm against XS by any means, but:
       *Foo::Bar::baz{CODE} = $coderef
    
    seems fairly straightforward...
      There are at least two reasons that I can think of..
      1. caller:
        sub whoami { print +(caller 1)[3], $/ } + *main::foo = sub { whoami() }; + foo(); __END__ main::__ANON__
      2. DProf:
        *main::foo = sub { sleep 1; }; + foo() for 1..5; __END__ $ perl -d:DProf foo.pl $ dprofpp tmon.out Total Elapsed Time = 5.00996 Seconds User+System Time = 0 Seconds Exclusive Times %Time ExclSec CumulS #Calls sec/call Csec/c Name 0.00 - -0.000 5 - - main::__ANON__
      When you have a lot of different anonymous subs floating around, it's a pain in the butt to profile, because all calls to anonymous subs land in main::__ANON__ as far as DProf is concerned.

      There's a trick involving local *__ANON__, which works for caller but not DProf.

      blokhead