Example 3: Polymorphic Cloning
Here's the cloneable mixin:
mixin cloneable {
public:
decltype(mixin)* clone() const override { return new decltype(mixin)(*this); }
}
class foo : public base {
public:
using mixin cloneable;
};
Functions in the mixin override functions the embedding class inherited.
The 'decltype(mixin)' construct names the embedding class. This is to save on
new keywords.
In addition, it might be useful to make it possible for mixins to have sections
that are not made visible to the embedding class (e.g. a "mixin:" access
specifier), although I am hesitant to really do this, because I can see a
pattern developing where the entire class body is always put in a mixin, and a
mixin: specifier is used to create "truly hidden" private sections.
Very interesting feature.
Questions:
1. does mixin member function have to be defined before the "using" call? does all the mixin code have to be in the declaration?
can it be mixins be written with declaration and definition separate? (the same question but said differently)
2.Example 3: Polymorphic Cloning
Here's the cloneable mixin:
mixin cloneable {
public:
decltype(mixin)* clone() const override { return new decltype(mixin)(*this); }
}
class foo : public base {
public:
using mixin cloneable;
};
Functions in the mixin override functions the embedding class inherited.
The 'decltype(mixin)' construct names the embedding class. This is to save on
new keywords.I don't understand why the return type of clone() is decltype(mixin)*.
If this clone() function is overloading base::clone(), then shouldn't it return base*?
If yes, then this clonable mixin should be templated with the base class as parameter.
Am I correct?
3.
Now if mixins have accessors inside, there seem to be several ways possibilities:
It would be better if you start from C++11 (or even the current draft; N3690 at this time)Example 1: Non-Copyable
class foo {
foo(const foo&) = delete;
foo& operator=(const foo&) = delete;
};
Example 2: Repetitive Operators (Boost.Operators, Boost.Iterator)
template <typename Derived>
class smart_ptr_base {
const Derived& self() const { return *static_cast<const Derived*>(this); }
typedef decltype(self.get()) T;
public:
T& operator *() const { return *self().get(); }
// etc.
};
template <typename T>
class my_ptr : public smart_ptr_base<my_ptr> {
T* get() const { return raw; }
};
- The CRTP's workings are unintuitive to those introduced to it - there's a reason it's called "curiously" recurring. In particular, the fact that Derived is an incomplete type in the body of the CRTP class is a common stumbling block, and the reason T must be passed along in the above example instead of determined by examining Derived (e.g. to look at a nested typedef). Function type deduction in C++14 can help in some cases, but not all.
- The class name must be repeated, including all its template arguments - the injected-class-name is not yet visible in the base specification.
- The interface that the CRTP base uses from the derived class must either be public, or there must be some friendship between the classes. Specifying the entire base class in a friend declaration can be annoying, and friending a type alias wasn't possible before C++11, which led to workarounds such as iterator_core_access (from Boost.Iterator).
Example 3: Polymorphic Cloning
You can do CRTP a lot better:Works in VS2012 already.. Note: there is no need to write my_ptr<T>, same reason why you don't write the template parameter out while defining the constructors.template <typename Derived>
class smart_ptr_base {
const Derived& self() const { return *static_cast<const Derived*>(this); }typedef decltype(self.get()) T;public:
T& operator *() const { return *self().get(); }
// etc.
};
template <typename T>
class my_ptr : public smart_ptr_base<my_ptr> {
T* get() const { return raw; }
};
Example 3: Polymorphic CloningIf you have polymorphic cloning, you have to have or your clone function virtual, otherwise you will call the base class' clone from the base pointer/reference. You mention macros as downside again, but even your virtual function example doesn't have any...
So sorry but -1. Mixins are dumbed-down versions of multiple inheritance so languages without that can have that functionality, but quite handicapped in a few cases. C++/CX is such a language, so it needs mixins, aka partial classes. There is absolutely no need for mixins in proper C++, as long as you use the language properly. It does need a few tweaks here and there, but I don't feel mixins are such.
=== Mixins (Class Extension Blocks) for C++ ===
Here's a non-copyable mixin:
mixin noncopyable {
noncopyable(const noncopyable&) = delete;
noncopyable& operator =(const noncopyable&) = delete;
}
class foo {
using mixin noncopyable;
};
Here, the compiler will fail to generate the copy functions for foo, because
they would have to call the mixin's copy functions, which are deleted.
Oppose this to a mixin solution:struct base {virtual base& foo() = 0;virtual base& foo() = 0;};
All your example cases can be solved with a good (private or public) base class, I try to show you how:It would be better if you start from C++11 (or even the current draft; N3690 at this time)Example 1: Non-Copyable(Side note: let me point out that noncopyable and noncopyassignable are two different things, although very frequently used together.)class foo {
foo(const foo&) = delete;
foo& operator=(const foo&) = delete;
};
The only thing is missing (?) is a standard std::noncopyable "mixin": the one above, with a correct name. This solution does not use macros, does not repeat the class name, and does not change the access classifier anywhere.
Base classes add a 'feature' to a class, some people say it is "is-a" relation. Saying that Foo is-a noncopyable thing isn't worse than Java or C# saying everything is-a Object, so I don't believe it is a misuse of base classes. I don't really see how an empty base class can screw up code generation, maybe with a bad compiler,
but in that case you are probably not even using C++11, or if the multiple inheritance is banned because of policy reasons, then you are asking a language extension because you don't use the whole language..Example 2: Repetitive Operators (Boost.Operators, Boost.Iterator)
You can do CRTP a lot better:Works in VS2012 already.. Note: there is no need to write my_ptr<T>, same reason why you don't write the template parameter out while defining the constructors.template <typename Derived>
class smart_ptr_base {
const Derived& self() const { return *static_cast<const Derived*>(this); }typedef decltype(self.get()) T;public:
T& operator *() const { return *self().get(); }
// etc.
};
template <typename T>
class my_ptr : public smart_ptr_base<my_ptr> {
T* get() const { return raw; }
};
- The CRTP's workings are unintuitive to those introduced to it - there's a reason it's called "curiously" recurring. In particular, the fact that Derived is an incomplete type in the body of the CRTP class is a common stumbling block, and the reason T must be passed along in the above example instead of determined by examining Derived (e.g. to look at a nested typedef). Function type deduction in C++14 can help in some cases, but not all.- The class name must be repeated, including all its template arguments - the injected-class-name is not yet visible in the base specification.None of this is true, see above example.
- The interface that the CRTP base uses from the derived class must either be public, or there must be some friendship between the classes. Specifying the entire base class in a friend declaration can be annoying, and friending a type alias wasn't possible before C++11, which led to workarounds such as iterator_core_access (from Boost.Iterator).Well, ok, you are right, but are you trying to give private functionality through a mixin? I fail to see where can that be useful.
Example 3: Polymorphic CloningIf you have polymorphic cloning, you have to have or your clone function virtual, otherwise you will call the base class' clone from the base pointer/reference.
You mention macros as downside again, but even your virtual function example doesn't have any...
So sorry but -1. Mixins are dumbed-down versions of multiple inheritance so languages without that can have that functionality, but quite handicapped in a few cases.
C++/CX is such a language, so it needs mixins, aka partial classes.
There is absolutely no need for mixins in proper C++, as long as you use the language properly. It does need a few tweaks here and there, but I don't feel mixins are such.
If something is missing, the standard "mixin" classes, starting with std::non_copyable, std::non_movable, and so on. Call for papers is until Friday, figure out what these are, and I help writing the proposal :)
Nice. I've been idly mulling the same topic for over a year now but hadn't really explored it as thoroughly as you have.I would definitely include accessors. The standard three to me make perfect sense. private implies only access to the mixin methods, protected is to the mixin or its mixed-into class/descendants, and public means, well, public.
I would also clarify that a mixin is not a type. You can't have a pointer to a mixin or such. It's essentially a block of syntactic sugar for a template-like mechanism (though unlike a templated type, it's still not a type). Spelling all the ramifications of this would be an undertaking, but it's IMO essential to what the core idea of a mixin is or how it could even be implemented reasonably.
You might consider how these could play with constraints, which is a feature that the CRTP method grants today (or once concepts lite are supported, anyway) but mixins do not.mixin foorequires(Comparable<*this>, is_base_of<base_type, *this>){ ... };If this is supported, then can you overload mixins like you can templates?
That is an incredibly simplistic example of the CRTP mixin pattern. Try a class that wants to use two mixins which each partially implement some of the polymorphic interface of a base. It gets unwieldly, quickly.
They aren't just that. C++'s multiple inheritance also does not solve certain problems. Mixins without MI aren't a complete solution. MI isn't a complete solution. Heck, mixins with MI probably won't be a complete solution, but it will be more complete at least.
And then there's the weird recursive situations, which granted are very exceptional in a good design, but I've seen come up several time. Example:struct base {virtual base& foo() = 0;virtual base& bar() = 0;};template <class Derived, class Base>struct mixin_foo : public Base {int value;Derived& foo() override;};template <class Derived, class Base>struct mixin_bar : public Base {void something(int);Derived& bar() override {something(static_cast<Derived&>(*this).value);return *this;}};struct derived : publix mixin_foo<derived, mixin_bar<mixin_foo<derived, ???>, base>>{int value = 5; // note that mixin_bar wants to use mixin_foo's value, not derived's value};
Oppose this to a mixin solution:struct base {virtual base& foo() = 0;virtual base& foo() = 0;};There's no way to realistically fill in the ??? part as mixin_bar's Derived type is itself dependent on mixin_bar. Again, it's a weird case, and every time I've seen it myself I've found other (arguably much better) ways to do what I wanted, but it is a general pattern that C++ multiple inheritance and CRTP are not an alternative to mixins. You can't _compose mixins_ with CRTP.
On 27 August 2013 16:14, Sebastian Redl <wasti...@gmx.net> wrote:=== Mixins (Class Extension Blocks) for C++ ===0. I would get rid of the references to how things were written back in the C++03 days. This is for C++17; it should be solving the things we can't (easily) write with C++14 and Concepts Lite.
1. Change the syntax by making the implicit template argument explicit, as in:template<typename T>mixin noncopyable{ /*... */ };This gives you a name for the type instantiated (instead of the weird decltype(mixin)) and makes it obvious it is templated. While it violates DRY (Don't Repeat Yourself), instantiating it should also require specifying T, as it is more uniform with the rest of the language.
For each of the following can you tell me if they are intended to be (a) copyable, (b) non-copyable or (c) non-compileable?
struct One {using mixin noncopyable;};
struct Two {using mixin noncopyable;Two(Two const&) = default;Two& operator=(Two const&) = default;};
struct Three {using mixin noncopyable;Three(Three const&) {}Three& operator=(Three const&) { return *this; }};
Nice that it works in VS2012. Have you actually tried instantiating it?It's still invalid, and won't compile in Clang or GCC. You can't use `this` (even implicitly) at the top level of a class, even inside a decltype. Even if you could, at that point the type Derived is incomplete and the get() call would be invalid. And finally, no, you can't omit the template arguments to my_ptr when passing it to the base class, because as [basic.scope.pdecl]p7 says, "The point of declaration for an injected-class-name (Clause 9) is immediately following the opening brace of the class definition." The opening brace is of course after the base class specifier, so the injected-class-name doesn't exist there.Now you could argue that these are defects in the standard, but the fact is that your "simple" CRTP example is currently not valid C++, and thus not a counterargument to my points.
Even if above example was valid, that wouldn't change the fact that it's still CRTP. I claim that CRTP by its very nature is not intuitive - saying, "but using CRTP doesn't need the extra boilerplate that you also complained about" doesn't contradict my core argument.
There is absolutely no need for mixins in proper C++, as long as you use the language properly. It does need a few tweaks here and there, but I don't feel mixins are such.I'm curious to hear what tweaks you think are necessary.
If something is missing, the standard "mixin" classes, starting with std::non_copyable, std::non_movable, and so on. Call for papers is until Friday, figure out what these are, and I help writing the proposal :)I have absolutely no interest in writing a hurried paper to get a few hacky special-purpose workarounds into the language.
Really what you're describing is another form of inheritance. Rather than being a superclass or subclass, the mixin is a peer of the target.
The tricky part is deciding the relative order of declaration and initialization of the mixin members.
C++11 is more sensitive than C++03 was to the declaration order of class members, because we have decltype() now. You could define the members at the using declaration, but this is a potential source of errors. (Unless you intended this, I'm not sure why you made it a using declaration rather than a base specifier.)
Some new syntax would be required to run the constructor of the mixin. It would be odd to mention a name from a using declaration in a constructor mem-initializer.
Nice that it works in VS2012. Have you actually tried instantiating it?It's still invalid, and won't compile in Clang or GCC. You can't use `this` (even implicitly) at the top level of a class, even inside a decltype. Even if you could, at that point the type Derived is incomplete and the get() call would be invalid. And finally, no, you can't omit the template arguments to my_ptr when passing it to the base class, because as [basic.scope.pdecl]p7 says, "The point of declaration for an injected-class-name (Clause 9) is immediately following the opening brace of the class definition." The opening brace is of course after the base class specifier, so the injected-class-name doesn't exist there.Now you could argue that these are defects in the standard, but the fact is that your "simple" CRTP example is currently not valid C++, and thus not a counterargument to my points.
Yes, of course, it works fine in every way. This was the compiler at hand, and I didn't try in other compilers, didn't think this can be nonstandard (MSVC surprises me every now and then in being nonstandard, but I think this is a convenient extension.)
Even if above example was valid, that wouldn't change the fact that it's still CRTP. I claim that CRTP by its very nature is not intuitive - saying, "but using CRTP doesn't need the extra boilerplate that you also complained about" doesn't contradict my core argument.
Instead ditching CRTP for an (in my opinion) infernal,
but more intuitive solution, adding more complication to the language without any real benefit, what about trying to make CRTP more intuitive?
Well, this list is the "C++ standard proposals", if people didn't think it needs tweaks here and there, it would been deserted long ago.
It's a pack of code.
struct base {
virtual base& foo() = 0;
virtual base& bar() = 0;
};
#define MIXIN_FOO \
int value; \
__THIS_CLASS__& foo() override;
#define MIXIN BAR \
void something(int); \
__THIS_CLASS__& bar() override { \
something(value); \
return *this; \
}
struct derived : public base
{
MIXIN_FOO
MIXIN_BAR
value = 5; //Meh - improvement area.
};Really what you're describing is another form of inheritance. Rather than being a superclass or subclass, the mixin is a peer of the target.
The tricky part is deciding the relative order of declaration and initialization of the mixin members. C++11 is more sensitive than C++03 was to the declaration order of class members, because we have decltype() now. You could define the members at the using declaration, but this is a potential source of errors. (Unless you intended this, I'm not sure why you made it a using declaration rather than a base specifier.)
Some new syntax would be required to run the constructor of the mixin. It would be odd to mention a name from a using declaration in a constructor mem-initializer.
Recently I suggested inferring member declarations from a concept applied to a template parameter used as a base class. A name that is required to exist doesn't really need to be considered type-dependent. Applied to an incomplete class, the principle could help bridge the gap that seems to be causing confusion in the above posts. Not to make a blanket judgment about this proposal, but CRTP can probably be improved by such relatively minor changes.
It's a pack of code.
Soooo.. a macro? What's wrong with macros, besides the awkward "generally good idea not to use them" argument? How about this macro-based solution to the problem:
The macro expands to the declaration of the two special members above, and in
some cases includes the access specifier. It has the following disadvantages:
- Uses the preprocessor.
- Repeats the class name.
- Changes the access specifier. OR Must be placed in private section.
I'm not at all convinced that macros are an equivalent solution and I
would rather prefer to stay away from it, where this is possible.
That's new: In every single language out there, mixin is a type. While C++ does not have to follow the same path, I think it is a bad idea to have something that is behaved differently than what every programmer with experiences in other languages think. Please don't name it mixin, if this says like it.
It's a pack of code.
Soooo.. a macro? What's wrong with macros, besides the awkward "generally good idea not to use them" argument?
How about this macro-based solution to the problem:struct base {
virtual base& foo() = 0;
virtual base& bar() = 0;
};
#define MIXIN_FOO \
int value; \
__THIS_CLASS__& foo() override;
struct derived : public base
{
MIXIN_FOO
MIXIN_BAR
Can be fixed with a __THIS_CLASS__-ish macro, the same way there is __FUNCTION__ or __PRETTY_FUNCTION__ in some implementations.
Macros are a hack. Every use of macros indicates a place where the core language is lacking.
Macros are part of the language. It will not go away. We have to live with this fact.
But with improvements (sorry, but everyone seem to miss that this is my point) it could also work in the place of mixins.
Same way as MI / CRTP could.
Either way, with "small" standard changes you could have what you need (with different syntax), and the language doesn't need an extra ~hundred pages describing every single current feature's interaction with the new mixin feature.
I don't know why you put "small" in quotes.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
I'm absolutely sure about adding the proposed mixin will wreak havoc among in almost every single clause of the language. It will be so complex you will (figuratively) never get your feature,
mixin cloneable {
cloneable* clone() const { return new cloneable; }
};
struct Foo {
using mixin cloneable;
};
struct Bar : public Foo {
};
using A = decltype(Bar().clone());
mixin noncopyable {
noncopyable(const noncopyable&) = delete;
};
struct Foo{
using mixin noncopyable;
};
struct Bar : public Foo {
Bar(const Bar&) : Foo() {}
}
How should mixins behave with inheritance, is it "inheriting" the mixin (so if descendants are also "using" it), or is ends there, descendants just get the members like they were defined normally?
Consider:Is type A equal to Foo* or Bar*? Is Bar cloneable?mixin cloneable {
cloneable* clone() const { return new cloneable; }
};
struct Foo {
using mixin cloneable;
};
struct Bar : public Foo {
};
using A = decltype(Bar().clone());
Consider:Is Bar noncopyable (conflicting with the copy constructor definition, making Bar ill-formed)?mixin noncopyable {
noncopyable(const noncopyable&) = delete;
};
struct Foo{
using mixin noncopyable;
};structBar : public Foo {
Bar(const Bar&) : Foo() {}
}
=== Mixins (Class Extension Blocks) for C++ ===
codegen noncopyable()
{
emit
{
decltype(class)(decltype(class) const&) = delete;
decltype(class)& operator = (decltype(class) const&) = delete;
}
}
This thing is not just a macro with better syntax, it is a fully-fledged constexpr function that can have compiletime-loops and use compiletime reflection to generate code. The only difference to a regular constexpr function is that it does not have a return type and instead emits code.Let's see how this can be used:
struct Foo
{
$noncopyable() // special call syntax could be using the $-sign or some other currently unused character
};
Another idea I had is a special "operator emit" that can be overloaded by classes to allow us to carry code around statefully. I have not yet put enough thought into this though.
On Wednesday, August 28, 2013 1:21:09 PM UTC+2, David Krauss wrote:Some new syntax would be required to run the constructor of the mixin. It would be odd to mention a name from a using declaration in a constructor mem-initializer.It's not a using declaration. It's a using mixin directive. ;-)
Yes, mixins can have constructors and destructors so that they can maintain their own invariants. And yes, I fully intend them to be called from the initializer list of the embedding class, using the mixin's name, mingled with the member variables of the class. I don't see why that's unintuitive, and especially not how new syntax would be any better.
Recently I suggested inferring member declarations from a concept applied to a template parameter used as a base class. A name that is required to exist doesn't really need to be considered type-dependent. Applied to an incomplete class, the principle could help bridge the gap that seems to be causing confusion in the above posts. Not to make a blanket judgment about this proposal, but CRTP can probably be improved by such relatively minor changes.Using concepts on the parameter of a CRTP base - interesting idea. I'm not sure how concept checks would work for incomplete types, though.
On Wednesday, August 28, 2013 8:07:11 PM UTC+8, corn...@google.com wrote:Yes, mixins can have constructors and destructors so that they can maintain their own invariants. And yes, I fully intend them to be called from the initializer list of the embedding class, using the mixin's name, mingled with the member variables of the class. I don't see why that's unintuitive, and especially not how new syntax would be any better.
Often the invariants for members are not established by the first line of the constructor body. A mixin depending on some functionality in the host class would expect invariants for the host members its constructor accesses.
The host class would in the general case need to call the mixin's constructor from its body. The same actually goes for destructors: the host destructor needs to relinquish the mixin at some point in its execution, not before beginning or after ending.
Maybe I'm making something out of nothing. There can always be initialize and finalize methods in addition to the constructor and destructor. Moving the calls of the constructor and destructor would wreak havoc with object lifetimes.
On the other hand, being able to defer initialization of a member whose constructor arguments require more preparation than can be accomplished in the mem-initializer-list would work around a longstanding issue. All we really need after all is to make UB use before initialization.
On Thursday, August 29, 2013 3:11:47 AM UTC+2, Róbert Dávid wrote:How should mixins behave with inheritance, is it "inheriting" the mixin (so if descendants are also "using" it), or is ends there, descendants just get the members like they were defined normally?
They just get the members. Anything else would be extremely confusing.
Consider:
Is type A equal to Foo* or Bar*? Is Bar cloneable?mixin cloneable {
cloneable* clone() const { return new cloneable; }
};
struct Foo {
using mixin cloneable;
};
struct Bar : public Foo {
};
using A = decltype(Bar().clone());
Bar does not have its own override of clone(). A is Foo*. Bar is still "cloneable" in the sense that you can call clone() on it, but it will do the wrong thing.
Consider:
Is Bar noncopyable (conflicting with the copy constructor definition, making Bar ill-formed)?mixin noncopyable {
noncopyable(const noncopyable&) = delete;
};
struct Foo{
using mixin noncopyable;
};
structBar : public Foo {
Bar(const Bar&) : Foo() {}
}
Bar is well-formed and copyable.
The ability to inject additional code into a class is something that I have repeatedly missed. Aside from a number of minor uses, I've twice found myself writing a library that would really have benefited from such a feature.
Since someone mentioned this feature a few days back, I thought I'd write up my thoughts on the matter and post them here to gauge interest and gather comments. Preliminary proposal below.
=== Mixins (Class Extension Blocks) for C++ ===
Hi,--- Purpose ---
Create a solution for injecting repetitive code into classes that has intuitive
syntax, doesn't use the preprocessor, and lacks the drawbacks of the CRTP.
--- Background ---
There's often a need for classes to contain somewhat repetitive code. For the
purpose of this document, we'll go with three motivating examples, in
increasing complexity.
I have used an alternative approach for mixins. A mixin is a metafunction having a Derived and a Base class. There is a base mixin that defines the self function and that has no Base parameter on the metafunction.
Example 2: Repetitive Operators (Boost.Operators, Boost.Iterator)
If I want to define my own smart pointer, here's what I have to do:
template <typename T>
class my_ptr {
// Custom storage logic.
T* raw;
public:
// Custom construction and destruction logic.
T* get() const {
// Custom access logic.
return raw;
}
// All these can be defined in terms of get():
T& operator *() const { return *get(); }
T* operator ->() const { return get(); }
// This was worse in C++03, when the safe-bool idiom had to be used.
explicit operator bool() const { return get() != nullptr; }
bool operator !() const { return get() == nullptr; }
};
Again, one could define a macro to encapsulate these operations, or a base
class. However, the base class solution has the problem that it needs to access
the get() function in the derived class. There are two possible ways to deal
with this.
<snip<
The second way is to use the Curiously Recurring Template Pattern:
template <typename Derived, typename T>
class smart_ptr_base {
const Derived& self() const { return *static_case<const Derived*>(this); }
public:
T& operator *() const { return *self().get(); }
// etc.
};
template <typename T>
class my_ptr : public smart_ptr_base<my_ptr<T>, T> {
T* get() const { return raw; }
};
The drawbacks of this solution are:
- The CRTP introduces its own boilerplate (the self() function).
- The CRTP's workings are unintuitive to those introduced to it - there's a
reason it's called "curiously" recurring. In particular, the fact that
Derived is an incomplete type in the body of the CRTP class is a common
stumbling block, and the reason T must be passed along in the above example
instead of determined by examining Derived (e.g. to look at a nested typedef).
Function type deduction in C++14 can help in some cases, but not all.
- The class name must be repeated, including all its template arguments - the
injected-class-name is not yet visible in the base specification.
- The interface that the CRTP base uses from the derived class must either be
public, or there must be some friendship between the classes. Specifying the
entire base class in a friend declaration can be annoying, and friending a
type alias wasn't possible before C++11, which led to workarounds such as
iterator_core_access (from Boost.Iterator).
--- Proposed Solution ---
Introduce a new code construct, the "mixin". A mixin is similar to a class, but
is not a type by itself. Instead, a mixin is embedded in (mixed into) a class;
its members become members of the class. A mixin is implicitly templated on the
type that embeds it, but can in addition have further template parameters. A
mixin is embedded in a class with a "using mixin" directive.
Example 1: Non-Copyable
Here's a non-copyable mixin:
mixin noncopyable {
noncopyable(const noncopyable&) = delete;
Does making mixins act like data member makes then increase the size of the class?noncopyable& operator =(const noncopyable&) = delete;
}
class foo {
using mixin noncopyable;
};
Here, the compiler will fail to generate the copy functions for foo, because
they would have to call the mixin's copy functions, which are deleted. The mixin
acts like a data member here, including the order of construction (i.e. when
data members and mixins are mixed, the constructors are called in the order of
declaration).
Have you considered adding a self keyword instead of using this?Example 2: Repetitive Operators
Here's the smart_ptr mixin:
mixin smart_ptr {
public:
// Could use decltype(auto) in C++14, but in some cases we can't, e.g. when
// we want to use SFINAE tricks on some overloads.
auto operator *() const -> decltype(*this->get()) { return *this->get(); }
auto operator ->() const -> decltype(this->get()) { return this->get(); }
explicit operator bool() const { return this->get() != nullptr; }
bool operator !() const { return this->get() == nullptr; }
}
template <typename T>
class my_ptr {
public:
T* get() const { return raw; }
using mixin smart_ptr;
};
To make this work, we need rules about the access to the embedding class from
the mixin.
Since the mixin is a template, the type of its 'this' pointer is dependent.
The syntax for acessing members is the same as that for access to members of
dependent base classes: use 'this->' to make the expression dependent and delay
lookup until instantiation time.
When the mixin is instantiated, the completeness of the embedding class is
treated exactly as if the mixin's code was directly embedded into the class,
i.e. members prior to the mixin directive are visible, those after are not, and
all the usual rules for ambiguity and changing meanings apply.
Mixins can contain access declarations. Their members have the more restricted
access of the one they have in the mixin and the one the mixin directive is
under. (POD: Just ignore the latter?)
Mixins can access all members of the embedding class, even private ones.
Example 3: Polymorphic Cloning
Here's the cloneable mixin:
mixin cloneable {
public:
decltype(mixin)* clone() const override { return new decltype(mixin)(*this); }
}
class foo : public base {
public:
using mixin cloneable;
};
Functions in the mixin override functions the embedding class inherited.
The 'decltype(mixin)' construct names the embedding class. This is to save on
new keywords.
Mixins can contain every kind of declaration that classes can, including inner
types, data members, and more mixin directives. Mixins cannot have base classes.
(POD: Should they be able to? The bases could be appended to the list of bases
of the embedding class. What kind of problems could that cause?)
I wouldn't consider this as an exception.On a side note, name conflicts can arise between the embedding class and mixins,
especially for nested types defined for utility, e.g. difference_type and
reference in the example above are defined in both the embedding class, and
the random access mixin. I believe that the best resolution rules are:
- Conflicting variables are an error, with the exception of static constants
with known values, which get merged if the values are the same.
The CRTP pattern allow to manage with this case as each mixin can relay on the base mixin. I see this is an advantage of the inheritance approach respect to the member approach.- Functions overload. If they cannot overload, it's an error.
Why using private as for class is not enough? What am I missing?- Types are merged if they are the same type.
In addition, it might be useful to make it possible for mixins to have sections
that are not made visible to the embedding class (e.g. a "mixin:" access
specifier), although I am hesitant to really do this, because I can see a
pattern developing where the entire class body is always put in a mixin, and a
mixin: specifier is used to create "truly hidden" private sections.
Could you show a concrete example and how the proposed mixin feature would help?On Tuesday, August 27, 2013 4:59:34 PM UTC-7, Róbert Dávid wrote:
That is an incredibly simplistic example of the CRTP mixin pattern. Try a class that wants to use two mixins which each partially implement some of the polymorphic interface of a base. It gets unwieldly, quickly.
And then there's the weird recursive situations, which granted are very exceptional in a good design, but I've seen come up several time. Example:
struct base {virtual base& foo() = 0;
virtual base& bar() = 0;};
Shouldn't this betemplate <class Derived, class Base>struct mixin_foo : public Base {int value;Derived& foo() override;};
template <class Derived, class Base>struct mixin_bar : public Base {void something(int);Derived& bar() override {something(static_cast<Derived&>(*this).value);return *this;}};
struct derived : publix mixin_foo<derived, mixin_bar<mixin_foo<derived, ???>, base>>{int value = 5; // note that mixin_bar wants to use mixin_foo's value, not derived's value};
Oppose this to a mixin solution:
struct base {virtual base& foo() = 0;
Sorry I missed the mixin solution?virtual base& foo() = 0;};
There's no way to realistically fill in the ??? part as mixin_bar's Derived type is itself dependent on mixin_bar. Again, it's a weird case, and every time I've seen it myself I've found other (arguably much better) ways to do what I wanted, but it is a general pattern that C++ multiple inheritance and CRTP are not an alternative to mixins. You can't _compose mixins_ with CRTP.
On Tuesday, August 27, 2013 5:54:43 PM UTC-7, Sean Middleditch wrote:
Oppose this to a mixin solution:
struct base {virtual base& foo() = 0;virtual base& foo() = 0;};
And I got distracted and cut short writing up that mixin example.
struct base {virtual base& foo() = 0;virtual base& bar() = 0;};
struct mixin_foo mixin {int value;auto decltype(*this) foo();};
struct mixin_bar mixin {
void something(int);auto bar() {something(this->value);
return *this;}};
struct derived : public base{
Oh, I've got it now. I don't see too much difference between the CRTP and the proposed mixin approach.using mixin mixin_foo;using mixin mixin_bar { using mixin_foo::value; } // sample syntaxint value = 5;};
I'm not super fond of the syntax there, but the idea is illustrated as well as it can for such a silly example I think.
Hi,
I agree that we need a way to inject repetitive code into a class. I'm not against not for your proposal. I would like just have more insight on the design rationale and why not try to help you to make a better proposal.
<snip>
I have used an alternative approach for mixins. A mixin is a metafunction having a Derived and a Base class. There is a base mixin that defines the self function and that has no Base parameter on the metafunction.
template <typename Base>
struct self_mixin {
template <typename Derived>
class type : public Base
{
public:
using Base::Base;
protected:
typedef Derived derived_type;
const Derived& self() const { return *static_cast<const Derived*>(this); }
Derived& self() { return *static_cast<Derived*>(this); }
};
};
template <typename T>
class smart_ptr_mixin
{
template <typename Derived, typename Base>
class type : public Base {
public:
using Base::Base;
public:
T& operator *() const { return *self().get(); }
// etc.
};
};
The use of these mixins is done as
template <typename T>
class my_ptr : public mixins<my_ptr<T>, self_mixin<>, smart_ptr_mixin<T> >
{
public:
T* get() const { return raw; }
// ...
};
mixins has as parameter the current class, and the list of mixins starting from the base one.
We could make define a MIXIN macro so that
template <typename T>
MIXIN(smart_ptr_mixin)
{
public:
T& operator *() const { return *self().get(); }
// etc.
};
is equivalent to
template <typename T>
class smart_ptr_mixin
{
template <typename Derived, typename Base>
class type : public Base {
public:
using Base::Base;
friend Derived;
public:
T& operator *() const { return *self().get(); }
// etc.
};
};
This approach solve some of the drawbacks you mention, while not all.
Does making mixins act like data member makes then increase the size of the class?
Have you considered to see them as part of the inheritance hierarchy?
class foo : public mixin X
{
};
Have you considered adding a self keyword instead of using this?Since the mixin is a template, the type of its 'this' pointer is dependent.
The syntax for acessing members is the same as that for access to members of
dependent base classes: use 'this->' to make the expression dependent and delay
lookup until instantiation time.
Mixins can contain every kind of declaration that classes can, including inner
types, data members, and more mixin directives. Mixins cannot have base classes.
(POD: Should they be able to? The bases could be appended to the list of bases
of the embedding class. What kind of problems could that cause?)
I don't see why the introduction of the last constraint is needed. With the CRTP model there is no such limitation
The CRTP pattern allow to manage with this case as each mixin can relay on the base mixin. I see this is an advantage of the inheritance approach respect to the member approach.- Functions overload. If they cannot overload, it's an error.
For example, several mixins could define a trace function that use the base one and add something else
void trace() {
this->base_type.trace();
// ....
}
Why using private as for class is not enough? What am I missing?In addition, it might be useful to make it possible for mixins to have sections
that are not made visible to the embedding class (e.g. a "mixin:" access
specifier), although I am hesitant to really do this, because I can see a
pattern developing where the entire class body is always put in a mixin, and a
mixin: specifier is used to create "truly hidden" private sections.
// etc.
};
};
The use of these mixins is done as
template <typename T>
class my_ptr : public mixins<my_ptr<T>, self_mixin<>, smart_ptr_mixin<T> >
{
public:
T* get() const { return raw; }
// ...
};
mixins has as parameter the current class, and the list of mixins starting from the base one.
I have actually developed a very similar system at one point, although it was C++03 and bound to one specific use case (which fixed the constructors and put a bound on the number of possible mixins, otherwise it would have been just horrible). It was still incredibly awkward to use, especially since I needed it in the public interface of the library I was developing at the time; people writing additional components within my framework would have had to use it. It was so bad that I scrapped the design completely.
Nested templates are simply ugly, and that's without trying to define some of the mixin's methods out-of-line; then you get to multiple template parameter lists, which I bet 90% of C++ programmers have never seen in production code, much less written.
We could make define a MIXIN macro so that
template <typename T>
MIXIN(smart_ptr_mixin)
{
public:
T& operator *() const { return *self().get(); }
// etc.
};
is equivalent to
template <typename T>
class smart_ptr_mixin
{
template <typename Derived, typename Base>
class type : public Base {
public:
using Base::Base;
friend Derived;
public:
T& operator *() const { return *self().get(); }
// etc.
};
};
No, you actually can't. You can't generate the second closing brace from the macro.
You could define the macro to expand to something like
class NAME {template <typename Derived, typename Base> class type;};template <typename Derived, typename Base> class NAME::type /* user continues here */
but that breaks for mixin templates, which require you to give the template parameter list and argument list forms to the macro, and then you run into the usual problems with commas in angle brackets in macro arguments, and even if you manage to solve it, it's one gigantic mess.
This approach solve some of the drawbacks you mention, while not all.
I don't really thinks it solves any of the drawbacks. The boilerplate may be somewhat reduced, if you manage to write the macro, but all the other points in my list remain unaffected.
Does making mixins act like data member makes then increase the size of the class?
Have you considered to see them as part of the inheritance hierarchy?
Mixins don't act like data members for any purpose but construction/destruction.
class foo : public mixin X
{
};
This runs into the problems I mentioned about the completeness of foo within the mixin.
Have you considered adding a self keyword instead of using this?Since the mixin is a template, the type of its 'this' pointer is dependent.
The syntax for acessing members is the same as that for access to members of
dependent base classes: use 'this->' to make the expression dependent and delay
lookup until instantiation time.
For a moment, but I don't see the point. 'self' is completely impossible to add, since it is widely used as a variable/function name, and the new use would be in a context where a variable name can appear. If you know any other conveniently short and logical words that aren't already in wide use in expression context, I'd love to hear about them, though.
Mixins can contain every kind of declaration that classes can, including inner
types, data members, and more mixin directives. Mixins cannot have base classes.
(POD: Should they be able to? The bases could be appended to the list of bases
of the embedding class. What kind of problems could that cause?)
I don't see why the introduction of the last constraint is needed. With the CRTP model there is no such limitation
The constraint isn't *needed*, it's just something that I didn't want to think about too hard. I would have to decide on the order of initialization, and from a compiler writer viewpoint, I'm not sure what it would mean to change the inheritance graph of a class in the middle of the body.
The CRTP pattern allow to manage with this case as each mixin can relay on the base mixin. I see this is an advantage of the inheritance approach respect to the member approach.- Functions overload. If they cannot overload, it's an error.
For example, several mixins could define a trace function that use the base one and add something else
void trace() {
this->base_type.trace();
// ....
}
This is a good point. Relaying calls from one mixin to another is a use case I haven't considered so far. I have no good solution for this at the moment.
Why using private as for class is not enough? What am I missing?In addition, it might be useful to make it possible for mixins to have sections
that are not made visible to the embedding class (e.g. a "mixin:" access
specifier), although I am hesitant to really do this, because I can see a
pattern developing where the entire class body is always put in a mixin, and a
mixin: specifier is used to create "truly hidden" private sections.
In the base class model, conflicting names just hide each other; they are not by themselves an error. But going with the model of inheriting conflicting names from multiple bases might be the best model for what I want to achieve after all.
Le 02/09/13 16:51, corn...@google.com a écrit :
Nested templates are simply ugly, and that's without trying to define some of the mixin's methods out-of-line; then you get to multiple template parameter lists, which I bet 90% of C++ programmers have never seen in production code, much less written.
Why would you need to define the mixin's methods out-of-line?
I don't see this as a problem, but a future of mixins. A mixin has only sense once instantiated.
class foo : public mixin X
{
};
This runs into the problems I mentioned about the completeness of foo within the mixin.
The keyword can be contextual.Have you considered adding a self keyword instead of using this?
For a moment, but I don't see the point. 'self' is completely impossible to add, since it is widely used as a variable/function name, and the new use would be in a context where a variable name can appear. If you know any other conveniently short and logical words that aren't already in wide use in expression context, I'd love to hear about them, though.
The alternative CRTP model would allow it without any trouble.This is a good point. Relaying calls from one mixin to another is a use case I haven't considered so far. I have no good solution for this at the moment.
Sorry, I don't understand. Are you telling inheriting from multiple bases?In the base class model, conflicting names just hide each other; they are not by themselves an error. But going with the model of inheriting conflicting names from multiple bases might be the best model for what I want to achieve after all.
On Monday, September 2, 2013 7:22:37 PM UTC+2, Vicente J. Botet Escriba wrote:Le 02/09/13 16:51, corn...@google.com a écrit :
Why would you need to define the mixin's methods out-of-line?Nested templates are simply ugly, and that's without trying to define some of the mixin's methods out-of-line; then you get to multiple template parameter lists, which I bet 90% of C++ programmers have never seen in production code, much less written.
Every other construct in C++ allows out-of-line definition; why should it be impossible for mixins?
I don't see this as a problem, but a future of mixins. A mixin has only sense once instantiated.
class foo : public mixin X
{
};
This runs into the problems I mentioned about the completeness of foo within the mixin.
I don't understand what you mean by that.
I want mixins to be able to refer to at least some members of the embedding class from the mixin body, not just the functions.
The keyword can be contextual.Have you considered adding a self keyword instead of using this?
For a moment, but I don't see the point. 'self' is completely impossible to add, since it is widely used as a variable/function name, and the new use would be in a context where a variable name can appear. If you know any other conveniently short and logical words that aren't already in wide use in expression context, I'd love to hear about them, though.
No, it can't be. That's what I've been trying to say with "would be in a context where a variable name can appear". Contextual keywords only work if the new use for the keyword is in a context where no existing identifier could appear. For example, the 'final' and 'override' contextual keywords only appear after the class name of a class declaration and after the parameter list of a member function; places where neither type names nor variable/function names are allowed. This allows them to be contextual keywords. A 'self' keyword would have to appear in expression context, in the place where e.g. 'this' can appear as well. More importantly, a variable named 'self' can appear in this place, and that's why 'self' doesn't work as a contextual keyword.
The alternative CRTP model would allow it without any trouble.This is a good point. Relaying calls from one mixin to another is a use case I haven't considered so far. I have no good solution for this at the moment.
A "rewrite to base classes" semantic model would work for many use cases, but not for the class member access I want. Also, initialization order would get interesting, and dealing with multiple mixins implementing functions from each other or multiple pre-existing base classes would bring lots of complexity in the definition and the explanation of the feature.
Motivating example:
struct Foo { virtual void foo() = 0; };struct Bar { virtual void bar() = 0; };mixin FooImpl {virtual void baz() = 0;void foo() { baz(); }}mixin BarBazImpl {void bar() {}void baz() {}}struct FooBar : Foo, Bar, mixin FooImpl, mixin BarBazImpl {};
Is the order of the mixins important here? What would the rewritten hierarchy look like?
Sorry, I don't understand. Are you telling inheriting from multiple bases?In the base class model, conflicting names just hide each other; they are not by themselves an error. But going with the model of inheriting conflicting names from multiple bases might be the best model for what I want to achieve after all.
Yes. Think about what happens when you inherit from multiple classes that have members with the same name. I think those are the best semantics for mixins with conflicting names too.
On Wednesday, August 28, 2013 12:50:14 AM UTC+2, Klaim - Joël Lamotte wrote:
3.
Now if mixins have accessors inside, there seem to be several ways possibilities:
You have pretty much enumerated the access possibilities given the current access specifiers. But my worry goes beyond just access and concerns visibility:
template <typename T>
mixin Foo {
using my_secret_helper_type = complicated_metaprogram<T>;
// how do I keep my_secret_helper_type from colliding with types in embedding classes?
// I can't open a namespace here, but I don't want to start with prefixes again
mixin:
using this_can_never_conflict = other_metaprogram<T>;
// awesome, I can use these without worries, because they're truly local to this class
}
I see these options to solve this problem:
1) Do nothing. Have the users use prefixes. This seems extremely inelegant to me.
1a) Merge what can be merged, but otherwise error out, as I described in my original post. Marginally better than 1).
2) Have declarations in the embedding class shadow those in mixins. Except for overloads maybe? But what if two mixins conflict? Earlier shadows later? Later shadows earlier? Declarations co-exist but are ambiguous when accessed?
2a) Embedding class shadows mixins, functions don't overload, multiple mixins coexist and are ambiguous in access. This is the "let's pretend we're still mixing in CRTP base classes" model. But given that I want the model to be "these are put into the class", that's very unintuitive.
3) Provide mixin: or an equivalent way of allowing mixins to hide their implementation details, and have other conflicting parts generate an error. Sounds reasonable, except that, as I said, this would mean that mixins provide a feature that C++ doesn't otherwise have, and I'm worried that they'll be used for that feature alone, leading to obfuscated code. But maybe I shouldn't be worried about that. I can still worry about implementability, though.
3a) Combine 3) with the merging from 1a) for non-hidden things. I like this merging - it feels intuitive and right. But maybe that's just because of where I'm coming from.
--Thanks for writing this down. I wanted to write pretty much the same for a few weeks now and never got to it :-)
For the things I have in mind, I would definitely need both
items.
Cheers,
Roland
Questions:
- Would data members be supported as well?
- Would a mixin be able to access the class that it is used by (similar to CRTP where the base object can access the derived object)?
For the things I have in mind, I would definitely need both items.
For the things I have in mind, I would definitely need both items.
<>--
Thanks for writing this down. I wanted to write pretty much the same for a few weeks now and never got to it :-)
You are welcome.
Questions:Yes. Types would be supported also.
- Would data members be supported as well?
Yes. This is at least my intent. A mixin has access to all the parts of its embedding class/mixin. This access rights need to be of course transitive.
- Would a mixin be able to access the class that it is used by (similar to CRTP where the base object can access the derived object)?
Do you have an idea for the syntax of accessing the embedding class/mixin yet?
You wrote earlier that mixin semantics should be defined via a transformation from CRTP. I'd be interested in that transformation. Do you think that transformation could be used for a formal proposal?
For the things I have in mind, I would definitely need both items.
The ability to inject additional code into a class is something that I have repeatedly missed. Aside from a number of minor uses, I've twice found myself writing a library that would really have benefited from such a feature.