David Precious <davidp@preshweb.co.uk> wrote:
One particularly good point made is that the current implementation stores the attributes for a given route handler by the refaddr, which could be problematic if run under threads (not sure if anyone really does that, though).
Moreover, if the coderef is a closure, refaddr isn't stable between compile time (when the attribute is applied) and run time (when the closure is created). But I believe this offers a workaround: # Returns an arbitrary non-reference value that should be stable across all # closures which are clones of (the same thing as) $coderef. sub subroutine_identity { my $coderef = shift; die "Not a CODE reference\n" if ref $coderef ne 'CODE'; my $cv = svref_2object($coderef); die "Not a CV\n" if !$cv->isa('B::CV'); my $op = $cv->START; return $$op; } What's this doing? B::svref_2object takes an arbitrary Perl reference, and returns an instance of the appropriate B class (B::CV in this case), representing the underlying object in the perl VM. Then $cv->START returns (a reference to) an integer representing the address of the first op in the subroutine. So this extracts a stable value that's guaranteed to refer to the underlying code rather than any of its closures. See also this thread on the perl-qa list: http://www.nntp.perl.org/group/perl.qa/2012/11/msg13303.html I haven't tried this in a threaded Perl, but it should work fine, because, AIUI, optrees are shared across cloned threads (even for closures created in different threads). Personally, I do like the attribute-based API in D::P::A::E, so I'd like to put in a plea for sticking with it. Unless I'm wrong about this approach working well enough, of course. :-) -- Aaron Crane ** http://aaroncrane.co.uk/