## Sunday, September 14, 2014

### Mixin Constraint on Self-typed Methods

This post illustrates the appropriate use of self-type to restrict the composition of (stackable) traits (mixins) in relation to an existing class or trait.

Overview
Mixin traits with self-type restriction has commonly used in Scala. Dependency injection and the Cake pattern in particular, relies on constraint imposed by a trait that it can be used only with subclass of a predefined types. The same approach can be used to constraint a trait to be used with class that support one or several methods.

Note: For the sake of readability of the implementation of algorithms, all non-essential code such as error checking, comments, exception, validation of class and method arguments, scoping qualifiers or import is omitted

Mixin constraint on self-type
Let's consider the case of a class taxonomy (or hierarchy) that classifies machine learning algorithms as either supervised learning or unsupervised learning.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 trait Learning { def predict(x: Double): Double { } } trait SupervisedLearning { def train(x: Array[Double]): Int = { ... } } trait Validation { self: SupervisedLearning => def validate(x: Array[Double]): Double } class SVM extends SupervisedLearning with Validation { override def train(x: Array[Double]): Int = { ... } } 

The support vector machine of type SVM is a type of supervised learning algorithm, and therefore extends theSupervisedLearning trait (line 5 & 115). The code snippet compiles because the class SVM (line 14) complies with the restriction imposed by the trait Validation on sub-types of SupervisedLearning (line 10).

  1 2 3 4 5 6 7 8 9 10 11 12 trait UnsupervisedLearning { def group(x: Array[Double]): int } // Validation: failed self-typed inheritance // from SupervisedLearning trait class EM extends UnupervisedLearning with Validation { override def train(x: Array[Double]): Int = { ... } } 

The Scala code snippet does not compile because the expectation-maximization algorithm, EM is an unsupervised learning algorithm and therefore is not a sub-class of SupervisedLearning.

Mixin constraint on self-typed method
Marking a trait to be extended (implemented) with sub-class with predefined method(s) is the same as marking a trait to be extended (implemented) with sub-class with predefined type.
Let's reuse the class hierarchy introduced in the previous section.

trait Validation {
self: { def train(x: Array[Double]): Int } =>
def validate(x: Array[Double]): Double = -1.0
}


This time around the Validation can be mixin with a class that implements the method train
As previously seen, the class SVM complies with the restriction imposed by the Validation. However the declaration of the reinforcement learning algorithm QLearning generated a compilation error because it does not implement the method train asd required.

// No training needed for Q-Learning
class QLearning
extends Learning
with Validation{

def predict(x: Double): Double { }
}


Although brief, this introduction to self-referential condition should help you to start considering this technique to protect you code from unintentional erroneous sub-typing and trait mixing.

References
Scala Cookbook A. Alexander O' Reilly 2013
The Scala Programming Language - M. Odersky, L. Spoon, B.Venners - Artima 2007