Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

How to fool caller() / use NEXT within a dynamic sub

by betterworld (Curate)
on Jul 26, 2005 at 18:49 UTC ( #478324=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monks,

I was looking for a way to change the current subroutine name to an arbitrary value (which is unknown at compile time), in order to have caller() return this value.

In particular, it is my ambition to inject a subroutine into an arbitrary package, and that subroutine should use NEXT, as the following code suggests:

use NEXT; no strict 'refs'; *{$package . '::function'} = sub { my $this = shift; # do something $this->NEXT::function(@_); };
Unfortunately, this piece of code does not work as expected, because NEXT will use (caller(1))[3] to determine the calling function, and that won't yield $package . '::function'.

You may verify this using the following script:

sub printcaller { my $caller = (caller(1))[3]; print "$caller\n"; } my $package = "testpackage"; *{$package.'::function'} = sub { printcaller(); }; testpackage::function();
The output is main::__ANON__, however I'd like it to be testpackage::function.

One possible solution would be eval, but I don't like this much:

sub printcaller { my $caller = (caller(1))[3]; print "$caller\n"; } my $package = 'testpackage'; eval qq{ sub ${package}::function { printcaller(); } }; testpackage::function(); # Output: testpackage::function

I know that I can trick caller() with goto &sub, however, I don't think that this gets me any further.

Does anyone know a solution to my problem?
Thank you very much.

Replies are listed 'Best First'.
Re: How to fool caller() / use NEXT within a dynamic sub
by chromatic (Archbishop) on Jul 26, 2005 at 19:57 UTC
    #!/usr/bin/perl use strict; use warnings; use Test::More tests => 1; sub printcaller { return ( caller(1) )[3]; } my $package = "testpackage"; { my $func_name = $package . '::function'; my $sub = sub { local *__ANON__ = $func_name; printcaller() }; no strict 'refs'; *{ $func_name } = $sub; } is( testpackage::function(), 'testpackage::function', 'tricked caller( +)!' );
      Thanks, this is really cool! Took me a while to understand it, though.
      I think I should write something like "package Dummy;" before messing around with the *__ANON__ typeglob to make sure not to pollute the namespace.

      OK, that's really cool, but Huh? Is there any documentation for that somewhere? (Other than reading the perl source code, I guess.)


      Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

        I haven't seen any documentation outside of reading gv.c. Ovid is the one who gave me the tip. My guess is that someone fooled around with Devel::Peek and found that anonymous globs have a special case to give them stash names.

        Is there any documentation for that somewhere?

        Well, as I indicated in my first posting in this thread, caller() would usually return something::__ANON__. So I guess that chromatic's idea is basically, 'Why not just make __ANON__ an alias to what we need?'.

        I don't know if this is documented; and probably I wouldn't have been able to work this out myself.

Re: How to fool caller() / use NEXT within a dynamic sub
by GrandFather (Saint) on Jul 26, 2005 at 19:53 UTC

    Why? Often an example of why you want to do something will make the question easier to understand, or suggest a better way to achieve what you are really trying to do.

    Perl is Huffman encoded by design.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://478324]
Approved by jeffa
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (6)
As of 2021-01-15 18:00 GMT
Find Nodes?
    Voting Booth?