Mix In programming is a style of software development where units of functionality are created in a class and then mixed in with other classes.
A mixin class is a parent class that is inherited from - but not as a means of specialization. Typically, the mixin will export services to a child class, but no semantics will be implied about the child "being a kind of" the parent.
A Mix In is also called an Abstract Subclass since Mix In can provide other services based on the services the original class provides.
Mixins are controversial because the prescribed way of providing such services is by association. However, they are useful because inheritance places the services within the child itself. For this reason they are commonly found in windows class libraries where there is a need for certain features to be generalized for "mixing in" later.
Actually Mixins are only 'controversial' because people try to use them in languages with no support for them. This makes all kinds of problems. See the Flavors mixins.
Also see Mixins For Cee Plus Plus
Mixins are coming from Flavors. Flavors is an early Object System for the Lisp Machine.
Imagine you have vanilla ice where you can add in different stuff. So the base class in Flavors was called Vanilla. Parts of the Lisp Machine operating system were programmed using mixins. An example is the window system, where you can mixin borders-mixins into window classes. So it does not mixin the borders itself, but adds the feature that the window has borders. In Flavors the classes slots are extended AND (and that is the big AND) the methods get extended OR overwritten, too. In the case of the border-mixin the idea is that it also extends (!!) the window-draw method to draw the borders.
Common Lisp also supports the mixin style of programming. Most other programming languages make it difficult, because they don't have Method Combinations.
See: David A. Moon. Object-oriented programming with Flavors. In Proc. First Annual Conference on Object-Oriented Programming Systems, Languages, and Applications. ACM, 1986.
An example for the mechanism using the Common Lisp Object System:
(defclass window () ((width :accessor window-width :initarg :width :type integer :initform 200)))
(defclass border-mixin () ((border-width :type integer :initarg :border-width :initform 1)))
This next function is the key element, which is not really possible in most object oriented languages. Most don't have :around, :before or :after methods. This facility is known as Method Combination.
(defmethod window-width :around ((window border-mixin)) (+ (call-next-method) (* 2 (slot-value window 'border-width))))
Now we define our own window class, which also inherits from our mixin class:
(defclass my-window-with-border (border-mixin window) ())
An instance:
(defvar *my-window* (make-instance 'my-window-with-border :width 400 :border-width 10)
We call the WINDOW-WIDTH method, which then runs the :AROUND method around the primary WINDOW-WIDTH method. So it computes (+ width (* 2 border-width)) :
(window-width *my-window*) -> 420
Do you really need full-fledged Method Combination, or is it enough to have a well-defined class-precedence list and the ability to call the next method in the list? I'm thinking of Dylan Language, which doesn't have Method Combination, but does copy Common Lisp's Generic Function paradigm, along with how to compute the class precedence list. It seems like the above example could be done just by translating the classes into Dylan syntax and then writing window-width like this:
define method window-width (window ::
)
next-method() + 2 * window.border-width; end window-width;
You do have to make sure that precedes in the class hierarchy for , but it seems like you would run into that problem even with CLOS if you ever tried to combine 2 or more mixins (since the various :around methods get ordered by the class precedence list too).
Well, in this case the ordering is not important for the CLOS example. All :AROUND methods are used.
In CLOS one could also use a + method combination, where the results of all methods get collected. So, you would define a bunch of WIDTH methods for the various elements that contribute to the window width and have them added by the method combination.
The word "mixin" comes from Steve's Ice Cream, a favorite ice cream shop of MIT students located in Somerville, Mass., in the late '70s. Steve's made its own (very rich) ice cream in a motorized old-fashioned ice cream maker in the window of the shop. Sometimes the line for an ice cream cone was out the door and down the block!
You would order a cone or dish, and specify the base flavor and any mixins you wanted. The person behind the counter would plop your scoop of ice cream on a marble slab, dump a spoonful of mixins on top, and knead the two together, using two metal spatulas. My personal favorite was chocolate ice cream with crushed Oreo cookies mixed in. -- Stan Silver
"The term mixin comes from an ice cream store in Somerville, Massachusetts, where candies and cakes were mixed into the basic ice cream flavors. This seemed like a good metaphor to some of the object-oriented programmers who used to take a summer break there, especially while working with the object-oriented programming language SCOOPS." (SAMS Teach Yourself C++ in 21 Days, 4th ed., p. 458.)
The grapevine informs me that Symbolics' object-oriented Flavors system is most likely the earliest appearance of bona fide mix-ins. The designers were inspired by Steve's Ice Cream Parlor in Cambridge, Massachusetts where customers started with a basic flavor of ice cream (vanilla, chocolate, etc.) and added any combination of mix-ins (nuts, fudge, chocolate chips, etc.). In the Symbolics system, large, standalone classes were known as flavors while smaller helper classes designed for enhancing other classes were known as mix-ins.
[From Chuck Esterbrook's article in Linux Journal #84 April, 2001 noframes.linuxjournal.com ]
One interesting way in which mixins are used in the Common Lisp Object System is by having them add to the list of applicable methods. E.g., you might have a class base, and a class derived, which want to specialize method foo. But you might also want to, say, add notification, as in an Observer Pattern. You create the observed-mixin, and do
(defclass derived (base observed-mixin) ())
(defmethod foo ((self base)) ;; do foo type stuff )
And the author of the mixin can write
(defmethod foo :after ((self observed-mixin)) (notify-all-observers (format nil "~A is being fooed!" self)))
This doesn't change anything to how foo acts on a derived, but lets all derived that want to be observed do so by simply inheriting the mixin. The use of the :before after :after methods that are part of the standard Method Combination makes this a handy pattern in the Common Lisp Object System.
In addition to the Common Lisp Object System, the Xo Tcl Extension (for the Tool Command Language) has good support for mixins.
Also see Mixins For Python
It has become doubtful as to whether Mix In techniques can be called polymorphism. According to Non Polymorphic Inheritance, using a Mix In does not entail delegation (see What Is Delegation), and so lacking the requisite indirection, does not have polymorphic behavior.
Delegation does not imply polymorphism (though in some cases it does). See Different Styles Of Delegation
This is true, but delegation + indirection = Poly Morphism. See What Is Delegation. Mix In does not require indirection.
I'm not sure I grok what you mean by "indirection" here -- polymorphism is usually defined in terms of type substitutability, however that is implemented. If you are referring to how vtables work (a virtual function call in Cee Plus Plus gets an extra level of indirection compared to a non-virtual call)...that's an implementation detail. An important one to be sure, but not fundamental to polymorphism.
Many other languages don't have vtables like C++, they perform name lookup at runtime.
Vtables or pick-your-preferred-implementation-details are not relevant, Poly Morphism is not fundamentally dependent on types, and focusing on substitutability has some subtle problems (see What Are Types).
Please grok Non Polymorphic Inheritance. The point made there is that a Mix In can be implemented without any polymorphism whatsoever. This kind of Mix In is for implementation reuse, not type substitution, and does not have polymorphic behavior.
Nobody pointed out Ruby Language in this page. Most of the Ruby world is based around Mix Ins via Modules. Worth noting that Observable is_a Mix In in ruby similar to the example class from Common Lisp Object System. Still, decorating methods is quite more ugly in Ruby. Ruby even allows you to add a Mix In to a single object like:
class << my_object include MixInModule end
Is this considered Allo Morphism?
-- I don't know what you mean by "decorating methods", so I'll have to re-read this page. -- Gavin Sinclair
I think it means method decorators, like ":before", ":after", ":around", etc. -- John Duncan
-- However, the Ruby concept/implementation of mixins is the complete opposite of ugly. For example, Comparable is a module (namespace for a collection of methods) that defines the methods <, <=, ==, !=, >=, and >, all based on the comparison operator "<=>". So I can define a class that can be compared - say Name, and then mix in the Comparable module to get all those methods for free:
class Name attr_accessor :first, :middle, :last # getter and setter methods def initialize(f, m, l) @first, @middle, @last = f, m, l end
# Here's the comparison operator. def <=>(other) [@first, @middle, @last] <=> [other.first, other.middle, other.last] end
# Here's the good bit - I get <, <=, etc. for free. include Comparable end
n1 = Name.new('John', 'Q', 'Smith') n2 = Name.new('John', 'M', 'Schmidt')
n1 < n2 # false n1 >= n2 # true # etc.
An even better example is the built-in Enumerable module, which provides methods like 'find', 'find_all', 'include?', 'map', 'sort', and several others, all based on the method 'each', which iterates over a collection. All of Ruby's collection-style classes therefore have all these methods. And if you write a collection-style class, you can 'include Enumerable' and get all these really powerful methods for free. Understanding Ruby's 'each' method is difficult for those not already familiar with Ruby, though. See Blocks In Ruby for that.
A little sample in Scala Language:
class Point2D(xc:
Int, yc: Int) {
val x = xc; val y = yc; override def toString() = "x = " + x + ", y = " + y; } class ColoredPoint2D(u: Int, v: Int, c: String) extends Point2D(u, v) { var color = c; def setColor(newCol: String): Unit = color = newCol; override def toString() = super.toString() + ", col = " + color; } class Point3D(xc: Int, yc: Int, zc: Int) extends Point2D(xc, yc) { val z = zc; override def toString() = super.toString() + ", z = " + z; } class ColoredPoint3D(xc: Int, yc: Int, zc: Int, col: String) extends Point3D(xc, yc, zc) with ColoredPoint2D(xc, yc, col);
And new ColoredPoint3D(1, 2, 3, "blue").toString() would return "x = 1, y = 2, z = 3, col = blue".
See also: the Traits Paper.
Having glanced briefly at much of this page and spent more time on a few parts, it seems that a lot of confusion and controversy could be prevented if we avoid using the language of inheritance to describe the Mixin. In particular, I find the first few lines talking about "inheriting" but saying the child is not the same kind of thing as the parent class contradictory. After all: long before anyone thought of applying the language of 'hierarchy' -- with all the implications from Aristotle's Categories -- to OOP, it has always been understood: the child is the same kind of thing as the parent, else the hierarchy is badly broken. Remember that this language was developed before anyone had to deal with the problems of hierarchies changing over time as evolution took place!
So I propose that instead of calling the classes 'parent' and 'child', and instead of saying the child 'inherits' from the parent, we should call the Mixin phenomenon "alien adoption", since this makes quite clear that the child is NOT the same kind of thing the parent is, but has only what the adopting parent has granted to it.
Is it not indeed the case that the use of Mixins really is different from OOP? If so, then this language makes that clearer, too.
See original on c2.com