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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With