Mantra mixins behave like Ruby mixins
Mixins behave like abstract superclasses except that a class may include more than one mixin (very much like multiple inheritance). Recall that abstract superclasses add functionality to subclasses and may refer to methods that don't have implementations in the abstract superclass. A subclass "includes" all of the methods and fields from the superclass except for those methods overridden in the subclass. A mixin differs only in that you do not have to provide abstract method declarations for undefined methods you call.
Philosophically, mixins differ from abstract base classes in an important way: mixins are just code and do not imply anything about identity. The superclass/subclass relationship, in contrast, is normally one of identity ("is a" relationship). For example, a manager "is an" employee and a house cat "is a" feline (well, some people think they are human). In contrast, a string is not a kind of Comparable object, but it does want to reuse comparison operators/code. Mixins in mantra provide the ability to share code without polluting the class hierarchy.
My desire for something like mixins came up when I realized that the exact same code for stream comparison should be included in all input streams. How do you do that without sharing the base class or duplicating code? After rolling back two other mechanisms designed to avoid duplicating code in the output, I settled on a simple include-like mechanism. The method bodies of mixin methods must be evaluated in the context of the class that includes them. It was just plain easier to reevaluate mixin methods in the proper context. The programmer still has a single method to change, but the generated code will see some duplication.
Mixins are valid type names in mantra because they are translated to interfaces in the output Java code. Mantra classes use the implements keyword as if the mixins it were interfaces. I was using includes but it didn't read as nicely. For example,
reads much better than "... includes Actor". Just doesn't make as much sense. I guess mixins are like interfaces that bring in some default implementation.
Here is an example mixin, taken from Ruby, that adds comparison operators to a class:
This mixin relies on method compareTo; all classes that include it must implement that method. Imagine you want to compare User objects. Rather than add operator methods to User, include Comparable:
Here's a sample usage:
The output is:
Classes only pull in those methods from mixins that are not defined directly in that class. Locally defined methods override those from mixins. In a sense classes override mixin methods.
Classes only pull in those fields from mixins that are not defined directly in that class.
If you include more than one mixin and method foo is defined in both, the foo from the first mixin is used. A "lint" tool could provide warnings.
One of the more useful mixins is InputStream that defines not only the basic interface but also some very useful support code: the equals method:
You cannot make all streams derive from a single base class. Mixins allow them all to share code; InputStream provides the equals method to all of the following classes:
1 Comment
comments.show.hideAug 13, 2008
Anonymous
You know Sather? It is a formerly promising but now sadly abandoned strongly-typed OO language with generics. It pushes even further the idea of code inheritance ("inclusion" in Sather parlance) vs. subtyping as two orthogonal concepts. In Sather you can not only choose what to inherit on a member-by-member basis, but also rename inherited stuff in the scope of the inheriting class! This includes the ability to rename features to nothing at all, i.e. remove them (you will have to implement them though, to comply with the interface). In addition there is a language construct called "partial class", a class that is explicitly marked as incomplete and designed to be "included" by other classes - i.e. "mixin".
Check it out: http://en.wikipedia.org/wiki/Sather