16

I use template mixins in C++ a lot, but I'm wondering why the technique isn't used more. It seems like the ultimate in reuse. This mix of power and efficiency is one of the reasons I really love C++ and can't see myself moving to a JIT language.

This article: http://www.thinkbottomup.com.au/site/blog/C%20%20_Mixins_-_Reuse_through_inheritance_is_good is a good backgrounder if you don't know what they are, and puts the case so clearly in terms of reuse and performance.

sbi
  • 219,715
  • 46
  • 258
  • 445
Jesse Pepper
  • 3,225
  • 28
  • 48
  • 4
    @GMan: I think the JIT reference is irrelevant to the question. It's a good question - it's an interesting design pattern which I've never seen in any of the code bases that I've worked on. – Skizz Jan 06 '12 at 09:14
  • @Skizz: It's totally irrelevant, I agree; but it's there. – GManNickG Jan 06 '12 at 09:20
  • +1: Never realized that this kind of technique can be used to implement mixins in C++ ! – neuro Jan 06 '12 at 09:35
  • I don't know any way of doing this in a JIT language. I'm not sure if that relates to them being JIT languages. – Jesse Pepper Jan 06 '12 at 09:53
  • Can any one suggest why people might think this should be closed? – Jesse Pepper Jan 06 '12 at 10:01
  • 1
    @JessePepper: I guess they consider it a "borderline" question, as the answers could be fairly subjective ("I have seen it a lot" type ?). As for JIT: it's not really a matter of JIT, more a matter of dynamic vs static typing. Dynamic typing makes it easier (syntaxically) since all the methods you write are "templates" in a C++ sense. Of course you pay the cost with runtime errors... – Matthieu M. Jan 06 '12 at 10:16
  • @MatthieuM not sure what you mean there. C++, C# and Java are all statically typed languages aren't they? – Jesse Pepper Jan 09 '12 at 07:31
  • @JessePepper: Yes they are. I don't understand where you question comes from though, I (and your question) never mentionned either C# or Java... – Matthieu M. Jan 09 '12 at 07:57
  • @MatthieuM: C# and Java are both JIT languages. I might be tempted to move to such a language if it had support for this kind of Mixin construct. There are probably too many other reasons why I wouldn't though, like RAII classes. Still, when I am forced to use C# or Java I would like to be able to use mixins. – Jesse Pepper Jan 09 '12 at 08:03

2 Answers2

23

The problem with mixins is... construction.

class Base1 { public: Base1(Dummy volatile&, int); };

class Base2 { public: Base2(Special const&, Special const&); };

And now, my super mixin:

template <typename T>
struct Mixin: T {};

Do you notice the issue here ? How the hell am I supposed to pass the arguments to the constructor of the base class ? What kind of constructor should Mixin propose ?

It's a hard problem, and it has not been solved until C++11 which enhanced the language to get perfect forwarding.

// std::foward is in <utility>

template <typename T>
struct Mixin: T {
  template <typename... Args>
  explicit Mixin(Args&&... args): T(std::forward<Args>(args...)) {}
};

Note: double checks are welcome

So now we can really use mixins... and just have to change people habits :)

Of course, whether we actually want to is a totally different subject.

One of the issues with mixins (that the poor article you reference happily skip over) is the dependency isolation you completely lose... and the fact that users of LoggingTask are then bound to write template methods. In very large code bases, more attention is given to dependencies than to performance, because dependencies burn human cycles while performance only burn CPU cycles... and those are usually cheaper.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • 1
    That overstates the practical problem a bit - can forward a small finite number of arguments with a little tedium (template explicit Mixin(const X& x) : T(x) { } template explicit Mixin(X&, Y&) : T(x,y) { }...), or a large finite number with a bit of ugly preprocessor invocation.... – Tony Delroy Jan 06 '12 at 09:40
  • 2
    @TonyDelroy: oh believe me people have tried. Given the combinations of `const`, `volatile` and `&` vs "value", it soon becomes untractable. Of course, for "one" particular case, it may work quite well, in general though it's difficult. And of course, as stated in the larger paragraph, while it's now technically feasible, it might still not be desirable for other reasons. – Matthieu M. Jan 06 '12 at 09:45
  • I have thought of using a class trait to solve this issue to some degree (though never got round to trying it!). The idea is that each mixin declares a nested type called, say, ModelTraits which includes a T::ModelTraits as a member. Note that this is a recursive recursive definition. The ModelTraits is used to initialise the class and the T::ModelTraits can be passed to the base class constructor. – Daniel Paull Jan 06 '12 at 09:48
  • @Daniel: This is a nice solution, however it becomes somewhat difficult when the base class has multiple constructors. – Matthieu M. Jan 06 '12 at 09:52
  • @Matthieu: except that in many code bases volatile's hardly ever used, and `const T&` vs. `T` is similarly typically irrelevant, so the multiplicative factor there is usually 2x for const and non-const. Again, tedium, but often practical :-(. The C++11 features are very welcome! – Tony Delroy Jan 06 '12 at 09:52
  • Well, the constructor parameter issue can be resolved using a two stage construction pattern, i.e. have an Initialise function that needs to be called after the object is constructed. The Symbian system does this (but that doesn't implement exceptions). It's not RAII, but that's the choice that needs to be made - RAII or Mixins - choose whatever is most appropriate. – Skizz Jan 06 '12 at 09:53
  • 3
    @Skizz You just answered your own question. RAII is way more popular and considered rather useful. – pmr Jan 06 '12 at 09:59
  • @Matt - agreed on multiple constructors. In my experience, mixins tend to be very small chunks of reusable code and only a default constructor. On rare occasions I have need to initialise the state of the mixin (note that many mixins are stateless as I tend to store state in a "model" fed into the base of the chain); in this case I tend to call some "init" or "set" method on the mixin class from the final class's constructor (almost two-stage construction as noted by Skizz). In the end, object initialisation has not been enough of a problem to make not want to use mixins! – Daniel Paull Jan 06 '12 at 10:02
  • @DanielPaull: Ah Okay... I admit I tend to call stateless mixins "Policy" as popularized by Alexandrescu in Modern C++ Design. – Matthieu M. Jan 06 '12 at 10:14
  • I think you could call it a "policy mixin" or "mixin policy". It certainly has the feel of policy based design but with the intention of chaining as seen in mixins. I think the blending of the idioms is very elegant and powerful. – Daniel Paull Jan 06 '12 at 10:49
  • Perhaps I should add a little more to my previous comment - the general approach of using multiple inheritance of policy classes allows a policy to be used only once within a class where as a mixin can appear multiple times in the mixin chain. I've used this fact many times (eg, to "mixin" a transform in a 3D drawing node which transform a part of the node - there is one transform mixin used per-part). – Daniel Paull Jan 06 '12 at 10:53
  • @DanielPaull: the policies may themselves be policed :) – Matthieu M. Jan 06 '12 at 10:56
  • 1
    @Matthieu: why are users of LoggingTask bound to write template methods? The article included a mixin to add the polymorphic base class, doesn't that work? – Steve Jessop Jan 06 '12 at 11:31
  • @Matt - policies with that have policies still aren't mixins :) – Daniel Paull Jan 06 '12 at 12:05
  • @SteveJessop: there are two aspects here. First, in the article, `MyTask` no longer has a `virtual` method (too slow they say) in the "Mixin" section, so passing a `LoggingTask` to a `foo(MyTask&)` would not log. Second, a method wanting a `LoggingTask&` as parameter need be templated. Unless they use a shim (template adapter inheriting from non-template base class) to circumvent the issue (but then they no longer take a `LoggingTask&` as parameter) – Matthieu M. Jan 06 '12 at 13:09
  • 1
    @Matthieu: They've offered that shim, though. *If* you want to avoid virtual calls, you write template functions. *If* you want to avoid template functions, you use `TaskAdapter` and pass it as an `ITask&`. They aren't claiming you can do both at once, but then neither does anybody else, and they do let you pick your preference. I agree about the constructors, I just don't think your additional criticism is justified. That said, there should probably be another polymorphic adapter, that takes the task it wraps by reference rather than by inheritance, to ease the boundary between the styles. – Steve Jessop Jan 06 '12 at 13:25
  • 1
    @Matt: (BTW - I wrote that article in case you didn't realise). The sole purpose of a Mixin is to help implement a concrete class. You will never, ever, ever find a Mixin in the wild; so there will never be a function that takes a LoggingTask& as a parameter. The way I use mixins is to inject common behaviour into a class that is implementing some pure-abstract interface. The only public interface to the instantiated object is this said pure-virtual interface. To bring it back to the article, MyTask would be declared and defined in a .cpp and a factory method exposed in a public header. – Daniel Paull Jan 06 '12 at 13:26
  • Btw I don't see why anyone would want, *a priori*, to take `LoggingTask&` as a parameter. By design it's a mixin, not an interface, so it's simply inappropriate to use it as a parameter type. [Edit - heh, I wrote that just as Daniel was writing the above. I guess he's not aiming to support the style with the template functions at all, although I'm pretty sure that in fact it is supported by the classes presented.] – Steve Jessop Jan 06 '12 at 13:29
  • @DanielPaull: I didn't realize. Therefore `MyTask` should inherit from `ITask` in the Mixin section as well should it not ? – Matthieu M. Jan 06 '12 at 13:40
  • @Steve: Yeah, there is nothing to stop a mixin class (like those defined in the blog post) being passed to a template function, and if/when it is useful, I would certainly do it. I just haven't come across a need for it and it smells fishy to me given the purpose of mixins (as I understand it to be and as I use it in my code base), but in a wider context perhaps there are valid reasons for doing it - I'd love to hear arguments for cases where it might be useful. – Daniel Paull Jan 06 '12 at 13:42
  • @Matt: Whether MyTask inherits from ITask itself or whether you use another mixin to pull it in is probably just an implementation detail. I tend to favour coupling to frameworks as late as possible. The TaskAdapter may be a bit cheeky, but I like it - the coupling to the ITask interface becomes a concern of the factory rather than a concern of the MyTask class. Holy decoupling Batman. – Daniel Paull Jan 06 '12 at 13:47
  • @Matthieu: I wouldn't - if you don't want logging or timing, then the class you actually pass is an `ITask&` is `TaskAdapter`. Although, since `TaskAdapter` is just there to help you write your concrete class, you're perfectly entitled to ignore all the mixins and just write `SomeTask` that implements `ITask`. But that class would be concrete, you wouldn't normally add mixins to it, and if you're using any mixins at all then you might as well make `TaskAdapter` one of them and everything else non-virtual. – Steve Jessop Jan 06 '12 at 13:50
  • @Daniel: I think the "need" for everything to be template functions is tenuous. Really it's a question of whether you'd *prefer* to attach yourself to the concrete class at compile time (templates) or at link time (polymorphic interfaces). Usually the answer to that is "please rebuild as little as possible when I run `make`", but not always. It probably comes down to whether you like the idea of template public interfaces at all -- if you don't then it's fishy. – Steve Jessop Jan 06 '12 at 13:56
  • @Steve: Well written mixins tend to be very stable, so I can't say that using mixins vs polymorphic interfaces and build times necessarily correlate! Personally, I tend to favour generic programming until it is impossible - for example, when components are loaded from plugin DLLs or the design dictates that the user composes things at run time. Anyway, the fishy part was regarding functions that take mixin classes as arguments - I still find that idea odd. – Daniel Paull Jan 06 '12 at 14:13
  • @Daniel: Well, it would be something like `template void do_task_twice(Task &task) { task.Execute(); task.Execute(); }`. I don't see why that's any more fishy than `void do_task_twice(ITask &task);` unless you need to compose late. – Steve Jessop Jan 06 '12 at 15:40
  • @Steve: the funtion you noted - `template void do_task_twice( T& t )` - is fine to me as it is a genereic function that can take _any type_ (yes, this includes mixin types, but the function writer did not write the function to take _only_ some mixin type). To clarify, what I mean is that I don't like the idea of a function that **takes a mixin type**, such as - `template void do_task_twice( SomeMixinType& t )`. This was directly in response to Steve's gripe about foo(MyTask&) and "a method wanting a LoggingTask& as parameter" - both seem fishy. – Daniel Paull Jan 07 '12 at 00:27
  • GCC 5.1 was unable to compile this code until I changed `std::forward(args...)` to `std::forward(args)...` *(note the end)*. Is that a typo in this answer? – Drew Dormann Jun 01 '15 at 14:42
5

Templates require implementation to be visible in the translation unit, not just at link time (C++11 addresses that if you'll only use a pointer or reference to instantiations). This is a major issue for low-level code in enterprise environments: changes to the implementation will trigger (might or might not be automatically) massive numbers of libraries and clients to recompile, rather than just need relinking.

Also, each template instantiation creates a distinct type, which means functions intended to work on any of the template instantions have to be able to accept them - either themselves being forced to be templated, or they need a form of handover to runtime polymorphism (which is often easy enough to do: just need an abstract base class expressing the set of supported operations, and some "get me a accessor" function that returns a derived object with a pointer to the template instantiation and related entires in the virtual dispatch table).

Anyway, these issues are typically manageable, but the techniques to manage the coupling, dependencies and interfaces involved are a lot less publicised, understood and readily available than the simple mixin technique itself. Same is true of templates and policy class BTW.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • I see the use of abstract interfaces as the primary way of avoiding coupling and thus compilation worries. I think it's a fair comment though. Our team is relatively small, but I do wonder if code bases need to necessarily be so huge and coupled. – Jesse Pepper Jan 06 '12 at 09:57
  • If I had to crown a way "primary", I'd definitely go with plain old out-of-line implementation (sans virtual dispatch), but both pImpl and abstract interfaces have their place too. Anyway, these things can be managed. Another technique is to have a non-templated front-end for the specific template instantiation you want, with the template directly supporting the out-of-line implementation but not visible via the header. Lots of options to reduce or control coupling, as well as options for facilitating easy movement between runtime and compiletime polymorphism. – Tony Delroy Jan 06 '12 at 10:12