Zydeco » Manual » 06_MethodModifiers

Method modifiers to easily wrap or override inherited methods

Synopsis

  package MyApp {
    use Zydeco;
    
    class Event {
      has date;
      method occur () {
        ...;
      }
    }
    
    class Wedding extends Event {
      before occur {
        say "Speak now or forever hold your peace";
      }
      after occur {
        say "You may kiss the bride";
      }
    }
  }

Zydeco allows subclasses to modify the methods they inherit from their parents, allow roles to modify the methods in the classes that consume them, and allow classes to modify the methods they consume from roles.

before and after modifiers.

A before modifier executes before the original method is called. Its return value is ignored. If it throws an exception, this will prevent the original method from being caused.

An after modifier executes after the original method is called. Its return value is also ignored.

Both of these modifiers may see the parameters passed to the original method.

  role Event {
    method set_host (Person $host) {
      ...;
    }
  }
  
  class LegalIssue with Throwable;
  
  class Wedding with Event {
    before set_host (Person $host) {
      $host->has_licence or LegalIssue->throw;
    }
  }

Like with method definitions, $self and $class are available.

Note that signatures are checked separately by the modifier and the original method. So it will be checked twice that $host is a Person object. Because checking is performed at run-time, for performance you may wish to simplify the signature in your modifiers.

  role Event {
    method set_host (Person $host) {
      ...;
    }
  }
  
  class LegalIssue with Throwable;
  
  class Wedding with Event {
    before set_host ($host) {
      $host->has_licence or LegalIssue->throw;
    }
  }

This is especially true for after modifiers, where the modifiers can be confident that the parameters have already passed the original method's signature checks.

around modifiers.

Unlike before and after modifiers, around modifiers can modify the arguments passed to the original method, can change the return value, and can even prevent the original method from being called. They allow you to wrap the original method in arbitrary ways.

Here's an example:

  package MyApp;
  use Zydeco;
  
  class PriceAdder {
    method add_prices ( ArrayRef[Num] $prices ) {
      my $sum = 0;
      $sum += $_ for @$prices;
      return $sum;
    }
  }
  
  class PriceAdder::WithCommission extends PriceAdder {
    has commission = 0;  # percent
    
    around add_prices ( $prices ) {
      my $sum = $self->$next( $prices );
      return $sum * ( 1 + ($self->commission/100) );
    }
  }
  
  my $adder = MyApp->new_priceadder_withcommission( commission => 5 );
  say $adder->add_prices( [ 100, 400, 500 ] );   # ==> 1050

Like with method definitions, $self and $class are available. $next is also defined which contains a coderef for the next method to call. This may be the original method itself, but it may be another wrapper.

If no signature is given, $next is passed as part of @_ before the invocant.

Keywords

In this chapter, we looked at the following keywords:

before
after
around
Next Steps

TODO.