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

Given a package
package Callback; sub do_callback { my $coderef = shift; $coderef->(@_); } 1;
and a class
package Parent; use Callback; sub new { bless {}, shift } sub do_something { ... } sub init { my $self = shift; my $coderef = \&do_something; Callback::do_callback($coderef, $self); } 1;
and a sub-class
package Child; use base qw(Parent); sub do_something { ... } 1;
then, in a nearby piece of code..
my $child = Child->new;

how can I pass values to Callback::do_callback() so that it calls the $child's do_something() method, without Callback knowing in advance that an object is expected?

I know that the ref of do_something() in package Parent will be that of the subroutine defined in that class.. but it seems like there should be a nice OOPy way of calling the correct method from a package external to where that method is defined.

Obviously this is a trivial example; in practice Callback might have to deal with unforeseen packages. Also assume that the guts of Callback can be examined but not modified.

Even if Callback knows to expect an object, calling

$obj->$coderef()

does not do The Right Thing.

If I've made myself clear, is there any way of achieving this functionality?

Replies are listed 'Best First'.
Re: Package coderefs
by chromatic (Archbishop) on Jan 20, 2005 at 00:29 UTC

    The simplest way without modifying your code is:

    Callback::do_callback(sub { $self->do_something() });

    I might instead add a callback_method() function that takes the name of a method to call and constructs a callback:

    sub callback_method { my ($method, $invocant) = splice( @_, 0, 2 ); $invocant->$method( @_ ); }

      Ouch. I was trying to avoid closures also. I thought perhaps there was a more direct way.

      Thanks for the response, though.

Re: Package coderefs
by Tanktalus (Canon) on Jan 20, 2005 at 03:49 UTC

    Wouldn't the following suffice?

    sub init { my $self = shift; my $coderef = $self->can('do_something'); Callback::do_callback($coderef, $self); }