Section 10.2. MIXIN TECHNOLOGY


10.2. MIXIN TECHNOLOGY

Our approach to increasing reuse is to build into programming languages better support for modularization and composition. To test this approach, we have developed the Java Layers (JL) language [12, 20], which extends the compositional capability of Java.

Java Layers extensions include support for constrained parametric polymorphism [11] and mixins. Parametric polymorphism allows types to be declared as parameters to code. Parametric polymorphism enhances reuse by allowing the same generic algorithm to be applied to different types; the collection classes in C++'s Standard Template Library [29] are an example of this kind of reuse. JL's implementation is similar to C++'s templates, but in keeping with most proposals [1, 2, 10, 19] for adding generic types to Java, JL allows type parameters to be constrained.

Mixins are types whose supertypes are specified parametrically. Mixins further enhance reuse over non-mixin parametric polymorphism by allowing the same subtype specialization to be applied to different supertypes. We give an example of mixin reuse in Section 10.2.1.

Mixin layers [27, 28] are a special form of mixins that can be used to coordinate changes in multiple collaborating classes. Mixin layers are mixins that contain nested types, which can themselves be mixins. Fidget, our GUI framework described in Section 10.3, is built using mixin layers.

10.2.1. Mixins

The term mixin was first used to describe a style of LISP programming that combines classes using multiple inheritance [21, 24]. Since then, the mixin concept has evolved to be that of a type whose supertypes are declared parametrically [9, 33]. We use the term in this sense and limit ourselves to languages such as Java that support single inheritance of classes. JL supports mixins and other generic types by implementing parametric classes and interfaces.

Mixins are useful, because they allow multiple classes to be specialized in the same manner, with the specializing code residing in a single reusable class. For example, suppose we wanted to extend three unrelated classesCar, Box, and Houseto have a "locked" state by adding two methods, lock() and unlock(). Without mixins, we would define subclasses of Car, Box, and House that each extended their respective superclasses with the lock() and unlock() methods. This approach results in replicating the lock code in three places.

Using mixins, however, we would instead write a single class called Lockable that could extend any superclass, and we would instantiate the Lockable class with Car, Box, and House. This approach results in only one definition of the lock code. In JL, the Lockable mixin would be defined as shown in Listing 10-1.

Listing 10-1. Lockable mixin in JL
 class Lockable<T> extends T {   private boolean _locked;   public lock(){_locked = true;}   public unlock(){_locked = false;} } 

This class is parametric, because it declares type parameter T. JL's parametric types are similar in syntax and semantics to C++ template classes. When Lock able<T> is compiled, T is not bound. To use Lockable<T>, T must be bound to a type to create an instantiation of the parametric class. Each distinct binding of T defines a new instantiated type, which can then be used like a conventional Java type.

What makes Lockable<T> a mixin, however, is that its instantiated types inherit from the types bound to T. Mixins are distinguished from other parametric types, because the supertypes of mixins are specified using type parameters. Thus, a mixin's supertypes are not precisely known at compile-time but instead are specified at instantiation-time.

Mixin instantiations generate new class hierarchies. For example, Lock able<Box> generates the hierarchy shown in Figure 10-2.

Figure 10-2. Lockable<Box> Hierarchy.


In its current form, Lockable's capabilities are limited, because nothing can be presumed about the type that gets bound to the type parameter T. In JL, however, constraints can be specified to restrict the types used in instantiations. For example, the redefinition of Lockable in Listing 10-2 guarantees that T's binding type implements the physical object interface (not shown). This constraint on T means members of PhysicalObject can be used within Lockable in a type-safe manner.

Listing 10-2. Redefining Lockable
 class Lockable<T implements PhysicalObject>   extends T {...} 

10.2.2. Stepwise Refinement

The GenVoca software component model [6] provides a conceptual framework for programming with mixins. The model supports a programming methodology of stepwise refinement in which types are built incrementally in layers. The key to stepwise refinement is the use of components, called layers, that encapsulate the complete implementation of individual application features. Application features are any characteristic or requirement implemented by an application. Stepwise refinement allows custom applications to be built by mixing and matching features.

Mixins implement GenVoca layers. To show how mixins can be used to build applications incrementally, we define the Colorable and Ownable mixins in the same way that we defined the Lockable mixin above. Colorable manages a physical object's color, and Ownable manages ownership properties. We can now create a variety of physical objects that support various combinations of features in Listing 10-3.

Listing 10-3. Incrementally building applications
 Colorable<Ownable<Car>> Colorable<Lockable<Box>> Lockable<Ownable<Colorable<House>>> 

We can think of each of these instantiations as starting with the capabilities of some base class, Car, Box, or House, and refining those capabilities with the addition of each new feature. In the end, a customized type supporting all the required features is produced. Mixins can be used in this way to provide some of the flexibility of multiple inheritance while avoiding pitfalls such as name collisions and repeated inheritance [33].

10.2.3. Mixin Layers

The compositional power of mixins can be increased with mixin layers. Mixin layers are mixins that contain nested types. A single mixin layer can implement a feature that crosscuts multiple classes. To see how this works, consider an example from our evaluation of customizable GUI libraries, which we call Fidget (Flexible widgets).

Listing 10-4 shows simplified versions of the basic Fidget class and the mixin layer that adds color support.

Listing 10-4. BaseFidget
 class BaseFidget<> {   public class Button {...}   public class CheckBox {...} ...} class ColorFidget<T> extends T {   public class Button extends T.Button {...}   public class CheckBox     extends T.CheckBox {...} ...} 

BaseFidget takes no explicit type parameters; we show two of its nested widget classes above. In the instantiation ColorFidget<BaseFidget<>>, the behavior of each of the nested classes in BaseFidget is extended by its corresponding class in ColorFidget. In this way, feature code scattered across multiple classes is encapsulated in a single mixin layer. In Section 10.3.4, we explain why some parameterized classes don't have explicit type parameters.



Aspect-Oriented Software Development
Aspect-Oriented Software Development with Use Cases
ISBN: 0321268881
EAN: 2147483647
Year: 2003
Pages: 307

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net