ZzZombo ZzZombo - 20 days ago 6
Perl Question

Distinguishing empty subroutines from subroutines with at least some minimal code

Is it possible in a way that doesn't involve deparsing the subroutine in question via

B::Deparse
or whatever back into its source form? The task at hand is to know whether a particular subroutine reference points NOT to a predeclared one w/o an actual body (like
package Foo;sub x :ATTR(...); ... sub x { ... }
), when an attribute (via
Attribute::Handlers
) is applied to it. At first I thought the
$code
parameter will be undefined in such case, but as it turned out it is not. While deparsing can be used for this task, as such subroutines return a mere
';'
as their decompiled code via
B::Deparse
, using it for large functions has its considerations, as well as dependency on this output across all versions of Perl, used modules, etc, etc. Not pretty.

Answer

I think I've found a solution w/o deparsing or size tests. Using the B module, I can query

my $cv=B::svref_2object($code);
undef $code if ref $cv->START eq 'B::NULL';

where if ref $cv->START eq 'B::NULL' in my, admittedly limited testing, is true only and only if a sub was only predeclared. It even filters out subs with no statements like sub x{}, exactly as I desire, unlike the former solution. My only gripe with this are possible differences across different Perl versions, but I couldn't find such info yet; I'm sticking to my current version anyway for the most part.

I've found it by a blind guess, I got pointed in the right direction by a book named "Perl Hacks: Tips & Tools for Programming, Debugging, and Surviving" by Chromatic, Damian Conway and Curtis Poe (link). It described how to find the largest subroutine in a module. So I hoped to rewrite the code to just get the size of a given subroutine, but the code was too heavy to be used in the project, including another CPAN module dependency. So I looked for another option, fiddled with CPAN B::TerseSize modules, until I found out they pretty much all use B in one way or another to do their thing. But looking at the documentation of the B module was a chore. Long story short, I just guessed START is the thing I'm looking for in the end, after furious printing of return values of various CV methods.

Comments