What Is a Mixin and Why Is It Useful

What is a mixin and why is it useful?

A mixin is a special kind of multiple inheritance. There are two main situations where mixins are used:

  1. You want to provide a lot of optional features for a class.
  2. You want to use one particular feature in a lot of different classes.

For an example of number one, consider werkzeug's request and response system. I can make a plain old request object by saying:

from werkzeug import BaseRequest

class Request(BaseRequest):
pass

If I want to add accept header support, I would make that

from werkzeug import BaseRequest, AcceptMixin

class Request(AcceptMixin, BaseRequest):
pass

If I wanted to make a request object that supports accept headers, etags, authentication, and user agent support, I could do this:

from werkzeug import BaseRequest, AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin

class Request(AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin, BaseRequest):
pass

The difference is subtle, but in the above examples, the mixin classes weren't made to stand on their own. In more traditional multiple inheritance, the AuthenticationMixin (for example) would probably be something more like Authenticator. That is, the class would probably be designed to stand on its own.

What are Mixins (as a concept)

Before going into what a mix-in is, it's useful to describe the problems it's trying to solve. Say you have a bunch of ideas or concepts you are trying to model. They may be related in some way but they are orthogonal for the most part -- meaning they can stand by themselves independently of each other. Now you might model this through inheritance and have each of those concepts derive from some common interface class. Then you provide concrete methods in the derived class that implements that interface.

The problem with this approach is that this design does not offer any clear intuitive way to take each of those concrete classes and combine them together.

The idea with mix-ins is to provide a bunch of primitive classes, where each of them models a basic orthogonal concept, and be able to stick them together to compose more complex classes with just the functionality you want -- sort of like legos. The primitive classes themselves are meant to be used as building blocks. This is extensible since later on you can add other primitive classes to the collection without affecting the existing ones.

Getting back to C++, a technique for doing this is using templates and inheritance. The basic idea here is you connect these building blocks together by providing them via the template parameter. You then chain them together, eg. via typedef, to form a new type containing the functionality you want.

Taking your example, let say we want to add a redo functionality on top. Here's how it might look like:

#include <iostream>
using namespace std;

struct Number
{
typedef int value_type;
int n;
void set(int v) { n = v; }
int get() const { return n; }
};

template <typename BASE, typename T = typename BASE::value_type>
struct Undoable : public BASE
{
typedef T value_type;
T before;
void set(T v) { before = BASE::get(); BASE::set(v); }
void undo() { BASE::set(before); }
};

template <typename BASE, typename T = typename BASE::value_type>
struct Redoable : public BASE
{
typedef T value_type;
T after;
void set(T v) { after = v; BASE::set(v); }
void redo() { BASE::set(after); }
};

typedef Redoable< Undoable<Number> > ReUndoableNumber;

int main()
{
ReUndoableNumber mynum;
mynum.set(42); mynum.set(84);
cout << mynum.get() << '\n'; // 84
mynum.undo();
cout << mynum.get() << '\n'; // 42
mynum.redo();
cout << mynum.get() << '\n'; // back to 84
}

You'll notice I made a few changes from your original:

  • The virtual functions really aren't necessary here because we know exactly what our composed class type is at compile-time.
  • I've added a default value_type for the second template param to make its usage less cumbersome. This way you don't have to keep typing <foobar, int> everytime you stick a piece together.
  • Instead of creating a new class that inherits from the pieces, a simple typedef is used.

Note that this is meant to be a simple example to illustrate the mix-in idea. So it doesn't take into account corner cases and funny usages. For example, performing an undo without ever setting a number probably won't behave as you might expect.

As a sidenote, you might also find this article helpful.

What is the difference between class and mixin in dart?

In Dart, a class can only extend one other class. But it can implement or mixin as many as you want.
The thing is, when you extend a class, you inherit all its attributes, methods and it's constructors. When you implement a class, if you are adding only methods/attributes that you don't already have, you can simply continue your code. If you are implementing an abstract method, you'll need to actually implement it. Now, mixins are like extended classes, the classes that mix them, are their child as well as with extend and implements, but it has no constructor.

The actual idea for mixins is that you can add functionalities to any class, and they don't have to extend another class. That's why they usually do simple stuff only.

What are the benefits of Mixin in Scala?

The assumption is that StringIterator is implemented independently. Perhaps, it is a member of some library, and you want to "enrich" it by adding some utility methods.

You can't make StringIterator extend your trait for that reason, it's not modifiable to you (another common situation when you don't want the class to directly extend the trait like that is when the functionality you are adding is only useful to some applications of the class, but not others).

You could do it the other way around, and make the "rich" trait extend the original class, like you did in your example. That works, but what if there are more than one? StringIterator, IntIterator, FileIterator, MyIterator, YourIterator ... Which one would you extend then?

Abstract classes vs. interfaces vs. mixins

Abstract Class

An abstract class is a class that is not designed to be instantiated. Abstract classes can have no implementation, some implementation, or all implementation. Abstract classes are designed to allow its subclasses share a common (default) implementation. A (pseudocoded) example of an abstract class would be something like this

abstract class Shape {
def abstract area(); // abstract (unimplemented method)
def outline_width() = { return 1; } // default implementation
}

A subclass might look like

class Rectangle extends Shape {
int height = width = 5;
def override area() = { return height * width; } // implements abstract method
// no need to override outline_width(), but may do so if needed
}

Possible usage

def main() = {
Shape[] shapes = { new Rectangle(), new Oval() };
foreach (s in shapes) {
print("area: " + s.area() + ", outline width: " + s.outline_width());
}
}

If a subclass does not override unimplemented methods, it is also an abstract class.

Interface

In general computer science terms, an interface is the parts of a program exposed to a client. Public classes and members are examples of interfaces.

Java and C# have a special interface keyword. These are more or less an abstract class with no implementation. (There's trickiness about constants, nested classes, explicit implementation, and access modifiers that I'm not going to get into.) Though the part about "no implementation" doesn't fit any more in Java, they added default methods. The interface keyword can be seen as a reification of the interface concept.

Going back to the Shape example

interface Shape {
def area(); // implicitly abstract so no need for abstract keyword
def outline_width(); // cannot implement any methods
}

class Rectangle implements Shape {
int height = width = 5;
def override area() = { return height * width; }
def override outline_width() = { return 1; } // every method in interface must be implemented
}

def main() = {
Shape[] shapes = { new Rectangle(), new Oval() };
foreach (s in shapes) {
print("area: " + s.area() + ", outline width: " + s.outline_width());
}
}

Java and C# do not allow multiple inheritance of classes with implementation, but they do allow multiple interface implementation. Java and C# use interfaces as a workaround to the Deadly Diamond of Death Problem found in languages that allow multiple inheritance (which isn't really that deadly, if properly handled).

Mixin

A mixin (sometimes called a trait) allows multiple inheritance of abstract classes. Mixins don't have the scary association that multiple inheritance has (due to C++ craziness), so people are more comfortable using them. They have the same exact Deadly Diamond of Death Problem, but languages that support them have more elegant ways of mitigating it than C++ has, so they're perceived as better.

Mixins are hailed as interfaces with behavioral reuse, more flexible interfaces, and more powerful interfaces. You will notice all these have the term interface in them, referring to the Java and C# keyword. Mixins are not interfaces. They are multiple inheritance. With a prettier name.

This is not to say that mixins are bad. Multiple inheritance isn't bad. The way C++ resolves multiple inheritance is what everyone gets all worked up about.

On to the tired, old Shape example

mixin Shape {
def abstract area();
def outline_width() = { return 1; }
}

class Rectangle with Shape {
int height = width = 5;
def override area() = { return height * width; }
}

def main() = {
Shape[] shapes = { new Rectangle(), new Oval() };
foreach (s in shapes) {
print("area: " + s.area() + ", outline width: " + s.outline_width());
}
}

You will notice there is no difference between this and the abstract class example.

One extra tidbit is that C# has supported mixins since version 3.0. You can do it with extension methods on interfaces. Here's the Shape example with real(!) C# code mixin style

interface Shape
{
int Area();
}

static class ShapeExtensions
{
public static int OutlineWidth(this Shape s)
{
return 1;
}
}

class Rectangle : Shape
{
int height = 5;
int width = 5;

public int Area()
{
return height * width;
}
}

class Program
{
static void Main()
{
Shape[] shapes = new Shape[]{ new Rectangle(), new Oval() };
foreach (var s in shapes)
{
Console.Write("area: " + s.Area() + ", outline width: " + s.OutlineWidth());
}
}
}

What is the difference between mixins and inheritance?

I'm not sure I understood your question properly, but if I did, you're asking how something can inherit without really meaning the same thing as inheriting.

Mixins, however, aren't inheritance – it's actually more similar to dynamically adding a set of methods into an object. Whereas inheritance says "This thing is a kind of another thing", mixins say, "This object has some traits of this other thing." You can see this in the keyword used to declare mixins: trait.

To blatantly steal an example from the Scala homepage:

abstract class Spacecraft {
def engage(): Unit
}
trait CommandoBridge extends Spacecraft {
def engage(): Unit = {
for (_ <- 1 to 3)
speedUp()
}
def speedUp(): Unit
}
trait PulseEngine extends Spacecraft {
val maxPulse: Int
var currentPulse: Int = 0
def speedUp(): Unit = {
if (currentPulse < maxPulse)
currentPulse += 1
}
}
class StarCruiser extends Spacecraft
with CommandoBridge
with PulseEngine {
val maxPulse = 200
}

In this case, the StarCruiser isn't a CommandoBridge or PulseEngine; it has them, though, and gains the methods defined in those traits. It is a Spacecraft, as you can see because it inherits from that class.

It's worth mentioning that when a trait extends a class, if you want to make something with that trait, it has to extend that class. For example, if I had a class Dog, I couldn't have a Dog with PulseEngine unless Dog extended Spacecraft. In that way, it's not quite like adding methods; however, it's still similar.



Related Topics



Leave a reply



Submit