开发者

Modern Perl: how to implement Redispatching Methods in AUTOLOAD()?

Feeling weak in OO topic i try to get improved with Modern Perl book. About asked topic i found in book following example:

package Proxy::Log; 

sub new
{
    my ($class, $proxied) = @_;
    bless \$class, $proxied;
}

sub AUTOLOAD
{
    my ($name) = our $AUTOLOAD =~ /::(\w+)$/;
    Log::method_call( $name, @_ );
    my $self = shift;
开发者_如何转开发    return $$self->$name( @_ );
}

Is this code just a scratch or working example?

I don't uderstand, how could i use it, where and what should it log and how should i create an object (what should get to $proxied)?

I added just few lines to test it, but got no AUTOLOAD-functionality:

package main;

my $tst = Proxy::Log->new();
say $tst->AnyKindOfSub();

I hope you could lead me to some working code with it. I thougt i got idea, how closures and AUTOLOAD works, but i am here a little jammed.


As bvr noticed, you have flipped your arguments to bless in the constructor. So while that is the immediate problem with your code, an important consideration when writing redispatching methods is to use the goto &sub syntax to erase the stack frame of the AUTOLOAD call:

sub AUTOLOAD
{
    my ($name) = our $AUTOLOAD =~ /::(\w+)$/;
    Log::method_call( $name, @_ );
    my $self = shift;
  # return $$self->$name( @_ );   # instead of this, use the following:
    unshift @_, $$self;           # setup argument list
    goto &{ $$self->can($name) }  # jump to method
}

If the redispatched method uses the caller builtin for anything (installing methods, localizing variables, Carp error reporting...), then this technique will keep caller working properly. Using the original return $$self->$name(@_) line would always report that caller was the last line of the AUTOLOAD sub, which in turn could be the source of hard to find bugs.

If you want to improve the error reporting a bit, you could write the last line as:

 goto &{ $$self->can($name) or Carp::croak "no method '$name' on $$self" };

Which assumes that the Carp package has been loaded.


I think the example have switched bless parameters in new of Proxy::Log. It probably should be:

bless \$proxied, $class;

Find below a functional example, as it was probably intended. The proxy class writes the log and then re-dispatch call to target object (Another class in example below).

package Proxy::Log;

sub new {
    my ($class, $proxied) = @_;
    bless \$proxied, $class;
}

sub AUTOLOAD {
    my ($name) = our $AUTOLOAD =~ /::(\w+)$/;
    warn "$name: @_";
    my $self = shift;
    return $$self->$name( @_ );
}

package Another;

sub new { 
    bless {}, $_[0];
} 

sub AnyKindOfSub {
    warn "Target called\n";
    return "Hello";
};


package main;

my $tst = Proxy::Log->new(Another->new);
say $tst->AnyKindOfSub();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜