Modern Perl: How to implement Redispatching methods in AUTOLOAD ()?

I am trying to improve the feeling of weakness in the topic of OO with the help of the Modern Perl book . I found about the given topic in the following example book:

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 a working example?

I don’t understand how I can use it, where and what it should register and how do I create an object (what should $proxied get)?

I added a few lines to check, but did not get the AUTOLOAD functionality:

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

I hope you can bring me to the working code. I got an idea how closures and AUTOLOAD work, but I'm a bit squeezed here.

+4
source share
2 answers

I think the example switched the bless options to new from Proxy::Log . This should probably be:

 bless \$proxied, $class; 

Find a functional example below as it was probably intended. The proxy class writes a log and then re-sends the call to the target ( Another class in the 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(); 
+4
source

As bvr noted, you turned your arguments over to bless in the constructor. Therefore, although this is an immediate problem for your code, an important consideration when writing re-mailing methods is to use the goto &sub syntax to erase the frame of the AUTOLOAD call AUTOLOAD :

 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 built-in caller for something (installation methods, variable localization, Carp error reporting ...), then this method will keep caller functional. Using the original line return $$self->$name(@_) will always report that caller was the last line of the AUTOLOAD sub, which, in turn, could be the source of hard-to-reach errors.

If you want to improve the error message a bit, you can write the last line as:

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

It is assumed that the Carp package has been downloaded.

+8
source

Source: https://habr.com/ru/post/1341278/


All Articles