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.
How do people get mixin-style re-use in C#?
In C#, the closest you get to C++ style mixins is adding the mixins as fields of a class and add a bunch of forwarding methods to the class:
public class MyClass
{
private readonly Mixin1 mixin1 = new Mixin1();
private readonly Mixin2 mixin2 = new Mixin2();
public int Property1
{
get { return this.mixin1.Property1; }
set { this.mixin1.Property1 = value; }
}
public void Do1()
{
this.mixin2.Do2();
}
}
This is usually enough, if you only want to import functionality & state of the mixins. A mixin can of course be implemented as you like, complete with (private) fields, properties, methods, etc.
If your class also needs to express "is-a" relationships with the mixins then you need to do the following:
interface IMixin1
{
int Property1 { get; set; }
}
interface IMixin2
{
void Do2();
}
class MyClass : IMixin1, IMixin2
{
// implementation same as before
}
(This is also the standard way how multiple inheritance is emulated in C#.)
Of course, the mixin interfaces as well as the mixin classes can be generics, e.g. with a most-derived class parameter or whatever.
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:
- You want to provide a lot of optional features for a class.
- 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.
Mixins and .net
I'm no expert, but this is what I found.
- Mixins in C# 3.0
- Implementing Mixins with C# Extension Methods
From MSDN Blog:
Mixins In C#
Some suggest that extension methods in
the upcoming C# 3.0 are a kind of
Mixins, because you can put in
functionalities in these methods and
arbitrarily tag it onto any class you
want. In the C# 2.0 specification
section 20.1.3 it is clearly called
out that the base class of a generic
class has to be a constructed class
type so this rules out using the above
approach to be used in C#. I am not
too sure on why we choose to
explicitly disallow abstract subclass.
Since C# does not support
multiple-inheritance, IMO it should
have supported Mixin style coding.
What is the difference between a variable and a mixin in sass?
From the sass documentation
Variables begin with dollar signs, and are set like CSS properties.
You can then refer to them in properties:
$width: 5em;
#main {
width: $width; // width is set as 5em
}
On the other hand, Mixins allow you to define styles that can be re-used throughout the stylesheet
@mixin large-text { // defining mixing
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}
.page-title { // applying mixin
@include large-text;
padding: 4px;
margin-top: 10px;
}
The above code is compiled to:
.page-title {
font-family: Arial;
font-size: 20px;
font-weight: bold;
color: #ff0000;
padding: 4px;
margin-top: 10px; }
scss mixin for custom css properties
You need to interpolate the $cssProperty
variable (so it becomes #{$cssProperty}
, just like you have done with the $side
variable. So your final code should be:
@mixin genericSidesStyles ($sides, $style, $cssProperty) {
@if($sides == '') {
#{$cssProperty}: $style;
}
@else {
@each $cssProperty, $side in $sides {
@if ($side == 'top' or $side == 'bottom' or $side == 'left' or $side == 'right' ) {
#{$cssProperty}-#{$side}: $style;
}
}
}
}
Related Topics
How to Create the Cartesian Product of a Type List
What Is the Maximum Length in Chars Needed to Represent Any Double Value
C++ Typedef Interpretation of Const Pointers
Blur Effect Over a Qwidget in Qt
Is Reading an Indeterminate Value Undefined Behavior
When Including Header Files, Is the Path Case Sensitive
Ncurses and Qt Interoperability
How to Get the Gl Library/Headers
Cancelling Boost Asio Deadline Timer Safely
What Is the Scope of a 'While' and 'For' Loop
Faq: Why Does Dynamic_Cast Only Work If a Class Has at Least 1 Virtual Method
Why Does a Std::Atomic Store with Sequential Consistency Use Xchg
How to Pass a Member Function to a Function Pointer
Portability of #Warning Preprocessor Directive