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

Im a regular abuser of AUTOLOAD, but would like to create customized routines for each invocation - essentially munging the method-name so its unique for each caller.

The following creates anonymous subroutines, then (in same statement) gives them a name by stuffing them in the symbol table. But once created, the method short-circuits any further AUTOLOAD invocation; the method is already built.

what I really need is enough optree-optimization fu to change the method-name in the caller code so that it can point to a name-munged method.

what I want to do is partly satisfied by $meth .= $line; but then the munged method, ex: auto_25(), wont be invoked by A::auto() called in main, and Im back to using AUTOLOAD as a dispatcher.

I have tried some lesser ways to achieve this, but no joy; code below attempts to put some context in arg-0, but is defeated by lack of CONSTANT-ness, a new {} is constructed each time, defeating a hash with munged method-names and a-sub refs.

#!/usr/local/bin/perl -w use strict; no strict 'refs'; package A; use Data::Dumper; use vars qw($AUTOLOAD); my %cache; sub AUTOLOAD { (my $meth = $AUTOLOAD) =~ s/.*:://; return if $meth eq 'DESTROY'; my ($package, $filename, $line, $subroutine) = caller(0); print "$meth called by: $package, $filename, $line, $subroutine\n" +; $cache{"$package, $filename, $line, $subroutine"} = $_[0]; $_[0]->{line} = $line; *{'A::'.$meth} = sub { print "invoking $meth from: $package, $filename, $line, $subroutin +e\n"; print "\twith ", Dumper (\@_); }; goto &{'A::'.$meth}; } package main; foreach (1..2) { # if hashref were CONSTANT, and not rebuilt for each invocation, # it could preserve the A::fancy({arb=>1},1); A::fancy({ok=>2},2); A::auto({}); A::auto({}); } use Data::Dumper; print Dumper (\%A::);
if you run this, youll find the line# reported is same for each call (due to closure on $line). I could get new $line for each invocation, but that defeats a main goal of using the a-sub (efficiency; avoiding unneeded caller()s).

Replies are listed 'Best First'.
Re: munging function names with AUTOLOAD
by perrin (Chancellor) on Jan 13, 2003 at 20:17 UTC
    It might be fun to mess with, but in my opinion this is not really worth your time if its not just for your entertainment. Using AUTOLOAD as a dispatcher is faster than you might think, and going to great lengths (magically rewriting opcodes in caller code!) to squeeze out that much performance is not worth the major obfuscation it will cause.

    If I really needed to do this and it wasn't fast enough using AUTOLOAD for dispatch, I would look at using a pre-processor and ditching AUTOLOAD altogether.

      your point is well taken - I use AUTOLOAD a lot, and have never found a need to do this. But AUTOLOAD is not the only overhead to be avoided - theres also stack walking that could be avoided.

      truth be told - this is for a possible patch to Log::Log4perl, whose authors are rightly concerned with performance, since the impact of inefficiencies can add up VERY quickly doing logging across an entire system.

      btw - Im starting to look at optimizer.pm - which may be the complete answer.. Any elaboration on this is welcome.

Re: munging function names with AUTOLOAD
by Abigail-II (Bishop) on Jan 13, 2003 at 22:02 UTC
    I'm not sure if I fully understand your problem. You are saying that the line number reported is the same for each call, but that's not quite true. You get two line numbers, which is logical, because you create two subs: A::fancy and A::auto. If you want to get the line number for each invocation, and not for each first invocation (when the sub is stuffed in the stash), there's a simple fix. Put the call to caller inside the anonymous sub, and not inside the AUTOLOAD routine.

    Abigail

      that last paragraph was something of a red-herring, I almost edited it out, cuz it wasnt the core of the question. It was an artifact of my probing. The same-ness was between invocations of the same function, ie from main, of fancy() on lines 33, 34, and of auto() on 35, 36. I left it in cuz I wanted to preclude tips on closures.

      my real issue is how to compile methods at 1st invocation and still have name munging - so that fancy_33 and fancy_34 are both built (which I can do) and called from the respective points in the caller code (which eludes me).

      that said, closures may well be part of the answer, esp as they can capture all/most-of the customizations w/o client participation (ie args carrying the customization parameters) tia.