I'm studying about mixins (in C++). I read some articles on mixins and found two different patterns of "approximating" mixins in C++.
Pattern 1:
template<class Base>
struct Mixin1 : public Base {
};
template<class Base>
struct Mixin2 : public Base {
};
struct MyType {
};
typedef Mixin2<Mixin1<MyType>> MyTypeWithMixins;
Pattern 2: (may be called CRTP)
template<class T>
struct Mixin1 {
};
template<class T>
struct Mixin2 {
};
struct MyType {
};
struct MyTypeWithMixins :
public MyType,
public Mixin1<MyTypeWithMixins>,
public Mixin2<MyTypeWithMixins> {
};
Are they equivalent practically? I'd like to know practical difference between the patterns.
They are different conceptually.
For the first pattern, you have decorators going (transparently) over a core functionality class, each adding their own twist/specialization to an existing implementation.
The relationship the first pattern models is "is-a" (
MyTypeWithMixins
is aMixin1<MyType>
specialization,Mixin1<MyType>
is aMyType
specialization).This is a good approach when you are implementing functionality within a rigid interface (as all types will implement the same interface).
For the second pattern, you have functionality parts used as implementation details (possibly within different, unrelated classes).
The relationship modeled here is "is implemented in terms of" (
MyTypeWithMixins
is aMyType
specialization, implemented in terms ofMixin1
andMixin2
functionality). In many CRTP implementation, the CRTP templated base is inherited as private or protected.This is a good approach when you are implementing common functionality accross different, unrelated components (i.e. not with the same interface). This is because two classes inheriting from Mixin1 will not have the same base class.
To provide a concrete example for each:
For the first case, consider the modeling of a GUI library. Each visual control would have a (for example)
display
function, which in a ScrollableMixin would add scroll-bars, if required; The scrollbars mixin would be a base class for most controls that are re-sizable (but all of them a part of the "control/visual component/displayable" class hierarchy.In this case, all mixin types would override (for example) a display method, and delegate parts of it's functionality (the specialized drawing part) to the decorated type (the base).
For the second case, consider a case when you would implement an internal system for adding a version number to serialized objects within the application. The implementation would look like this:
In this case, both
database_query
anduser_information
store their settings with a version number, but they are in no way in the same object hierarchy (they don't have a common base).The difference is visibility. In the first pattern,
MyType
's members are directly visible to and usable by the mixins, without any need for casting, andMixin1
's members are visible toMixin2
. IfMyType
wants to access members from the mixins, it needs to castthis
, and there isn't a great way to do so safely.In the second pattern, there is no automatic visibility between the type and the mixins, but the mixins can safely and easily cast
this
toMyTypeWithMixins
and thereby access the members of the type and of other mixins. (MyType
could too, if you applied the CRTP to it too.)So it comes down to convenience versus flexibility. If your mixins are purely accessing services from the type, and have no sibling dependencies of their own, the first pattern is nice and straightforward. If a mixin depends on services provided by the type or other mixins, you're more or less forced to use the second pattern.