re-motion mixins basics -- overriding mixin methods

Having a target class overriding a mixin's method is easy to implement – just use the OverrideMixin attribute. In the following code sample, the programmer is impatient with the OnThePhoneMixin's Wait method and writes his own for the Parrot class. This overriding Wait slashes the milliseconds in half:

  [Uses (typeof(OnThePhoneMixin))]
  public class Parrot
  {
    public virtual void Whistle ()
    {
      Console.WriteLine ("'River Kwai march' here...");
    }

    public virtual void Say (string s)
    {
      Console.WriteLine ("\"{0}\"", s);
    }

    // The 'Wait' method is part of the 'IOnThePhone' interface,
    // implemented by the 'OnThePhone' class, which brings its own
    // 'Wait' implementation. We override that method here. The
    // 'OnThePhone's 'Wait' method must be virtual for this to 
    // work
    [OverrideMixin]
    public virtual void Wait (int milliseconds)
    {
      Console.WriteLine ("[The parrot's (overridden) method]");
      Thread.Sleep (milliseconds / 2);
    }
  }

OverrideMixin only works if the mixin class is derived from the generic type Mixin<TThis> or Mixin<TThis, TBase>, as discussed in re-motion mixins basics -- overriding target methods#Target overrides Mixin?. This is the reason why the dessert wax sample listed in re-motion mixins basics -- overriding target methods#Target overrides Mixin? won't work (as hinted in the discussion following the listing).

The sophistication of the OverrideMixin attribute lies not so much in the how, but in the when and why.

When to use the OverrideMixin attribute

Note that in the example above we have attributed the target class with Uses instead of the mixin class with Extends. As pointed out on the wiki-page re-motion mixins basics -- the 'Uses' attribute and the 'ObjectFactory'#Using {{Uses}}, this is the rare case. In practice, the Extends attribute for attributing the mixin class is far more popular.

This situation is reversed for target classes overriding mixin methods, because the presence of the OverrideMixin attribute nullifies the assumption that target classes shall be independent of what is mixed to them. Think about it: If the mixin class already knows it is supposed to extend a particular target class (and therefore attributed with Extends), then it would probably be cleaner to subclass the mixin class, override the method in that subclass and use the subclass for mixing. So when is it useful to use Uses and OverrideMixin?

This question is not easy to answer. The next section on this page explains how to use OverrideMixin productively for the template method pattern.

The template method pattern

The template method pattern is useful for adding a "plan" or "procedural knowledge" to a target class. The wikipedia article on the subject gives the example of a simple engine for board games. The Chess and Monopoly specializations provide the methods for

  • initializing the board (and the bank, in the case of monopoly)
  • determining when a game has ended
  • determining who has won

The superordinate "template", the abstraction of how to conduct such a board game, is encoded in the base class.

If you look at our Parrot class (hierarchy) and the OnThePhoneMixin you will see something very similar:

  • the Parrot class knows how to say a given string
  • the OnThePhoneMixin class with its PretendToTalkOnThePhone method is the plan and the procedure of what to say when to give the audience the illusion that the speaker is having a phone conversation

The author believes that putting the "template", the "plan" or "procedure" into an extra mixin class is a much cleaner way of implementing the template method pattern than the route of implementation inheritance given in the wikipedia article, because it is more flexible.

For this scheme to work, the target class must be able to override methods from the mixin implementing the template. Specializations might require to modify some (or even all) methods, but other specializations might be served well by the defaults provided by the template. In the contrived parrot example from the beginning of this page, the specialization was that the template's Wait method waited for too long, for example.