This document describes the extension of Smalltalk with mixins. The motivation for this proposal is the desire for increased code sharing. Smalltalk has a clean and simple single inheritance semantics. However, this can sometimes result in undesirable code replication. Mixin based inheritance [BrachaCook90, Bracha92] does not introduce the complications associated with multiple inheritance . It preserves the simple semantics of Smalltalk subclassing and message lookup, while allowing a large degree of code sharing. It is therefore desirable to try and incorporate mixins into Smalltalk.
A mixin specifies a set of modifications (overrides and/or extensions) to be applied to a superclass parameter. A mixin differs from an ordinary subclass definition in that it abstracts over the identity of its superclass. Mixins may be viewed as functions that take superclasses and produce subclasses. Consider the following pseudo-code :
Point subclass ColorPoint
instance variables: red green blue
methods:
red: r green: g blue: b
hue: h saturation: s value: v
red
green
blue
hue
saturation
value
The code in ColorPoint has little to do with points. It applies to a variety of colored graphical entities. Replicating the color specific code in a variety of places is undesirable. An easy and natural way to achieve this to incorporate the code into a mixin:
Mixin Color(G) {
G subclass {
instance variables: red green blue
methods:
red: r green: g blue: b
hue: h saturation: s value: v
red
green
blue
hue
saturation
value
}
}
The mixin Color abstracts over an unspecified superclass G. Color can then be used at different points in the subclass hierarchy, by invoking it on different actual superclasses, much as one invokes a function at multiple points in a computation. This is accomplished using |>, the mixin invocation operator :
ColorPoint = Color |> Point
ColorCircle = Color |> Circle
The |> operator takes a mixin M and a class S, and produces a new class that modifies its superclass S with the code defined in M. The mixin can be applied to various superclasses to derive different classes. However, the source code of the mixin is shared among all these mixin applications, promoting modularity. The analogy between mixins and functions is useful in understanding the properties of mixins. Here are some key points:
See [BrachaCook90, Bracha92} for a more extensive discussion of mixins.
In Smalltalk, every class is itself a first class object with its own identity, and potentially with its own class and instance variables. It follows that every mixin invocation produces a distinct class, with a distinct identity, as its result. This is essential to prevent syntactically identical invocations (possibly in different libraries) accidentally sharing state with unforseen consequences.
It is often desirable to treat an existing class as a mixin. S mixin returns a mixin that contributes the definitions given locally by the class S. Consider the case of a class in a library of graphical widgets:
Widget subclass AgregateWidget{...}
Such a class groups widgets together. It is useful to think of this class a collection of widgets. However, one cannot usually inherit functionality from Collection since graphical widgets belong to a separate hierarchy. By revising the definition to
Collection mixin |> Widget subclass AgregateWidget{...}
one can reuse all of the functionality in the Collection class.
Mixins do not change the semantics of subclassing or of message lookup in Smalltalk. As a result, mixins do not influence the behavior of existing Smalltalk programs. The extension is therefore fully upward-compatible. Furthermore, mixins can easily be eliminated from a program by automatically creating a class for each mixin invocation, and duplicating the mixin's code in it.
In principle, mixins are easily implemented using Smalltalk's reflective capabilities. One can simply enclose a class constructor within a method that takes a superclass and a name as arguments. The method must also reflectively add the required methods to the new class. Of course, this solution is too awkward to be useful in practice. A usable implementation must provide programming environment support for creating and incrementally modifying mixins. Whenever a change is made to the mixin, it must be propagated to all invocations, and checked for validity. More ambitious implementations may seek to share code among a mixin's invocations.
A working implementation of mixins in Smalltalk has been constructed. Mixins have been used in the construction of real applications, and the code sharing benefits have been significant. In particular, the ability to extract mixins from existing classes has proven very valuable. Further experience is necessary, however, to to determine how extensively one should use mixins, and to establish a methodology of working with mixins.
Mixin based inheritance can easily be added to Smalltalk without changing the existing semantics of Smalltalk subclassing and method lookup. Preliminary experience with a working implementation indicates that the extension fullfills its goal of increasing code sharing, without the complications inherent in multiple inheritance.
[BrachaCook90] Gilad Bracha and William Cook. Mixin-based inheritance. In Proc. of the Joint ACM Conf. on Object-Oriented Programming, Systems, Languages and Applications and the European Conference on Object-Oriented Programming, October 1990 .
[Bracha92] Gilad Bracha, The Programming Language Jigsaw: Mixins, Modularity and Multiple Inheritance, Ph.D. dissertation, Dept. of Computer Science, University of Utah 1992.