Prev: constexpr array function pointers as fast as switch
Next: compilation error when Base Constructor calling pure virtual method
From: DeMarcus on 6 Jul 2010 04:15 Hi, As I understand, Policies have been widely accepted, but is it the same with Mixins? Or does people still believe Mixin is a bad way to avoid Liskov's IS-A principle? My latest Mixin looks like this. template<class T> class CopyMixin { public: typedef std::shared_ptr<T> SPtr; SPtr copy() const { // Use NVI. return copy_(); } protected: virtual SPtr copy_() const = 0; }; class SomeClass : public CopyMixin<SomeClass> { private: virtual SPtr copy_() const { SPtr c = /* Make a proper deep copy. */ return c; } }; What do you think about Mixins in general? And if you have time, what do you think about above CopyMixin? (Maybe a better copy mixin is already invented. If you know of any, please show me.) Thanks, Daniel -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Mathias Gaunard on 6 Jul 2010 11:19 On Jul 6, 8:15 pm, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote: > Hi, > > As I understand, Policies have been widely accepted, but is it the same > with Mixins? Or does people still believe Mixin is a bad way to avoid > Liskov's IS-A principle? > > My latest Mixin looks like this. > > template<class T> > class CopyMixin > { template<typename T, typename Base = some_empty_class_type> class CopyMixin : Base { is better since it allows you to avoid multiple inheritance. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Andy Venikov on 6 Jul 2010 11:19 DeMarcus wrote: > Hi, > > As I understand, Policies have been widely accepted, but is it the same > with Mixins? Or does people still believe Mixin is a bad way to avoid > Liskov's IS-A principle? > > My latest Mixin looks like this. > > template<class T> > class CopyMixin > { > public: > typedef std::shared_ptr<T> SPtr; > > SPtr copy() const > { > // Use NVI. > return copy_(); > } > > protected: > virtual SPtr copy_() const = 0; > > }; > > > class SomeClass : public CopyMixin<SomeClass> > { > private: > virtual SPtr copy_() const > { > SPtr c = /* Make a proper deep copy. */ > return c; > } > }; > > > What do you think about Mixins in general? > > And if you have time, what do you think about above CopyMixin? > (Maybe a better copy mixin is already invented. If you know of any, > please show me.) I'm afraid you're confusing mix-ins with CRTP (curiously recurring template pattern). Your CopyMixin is not a mix-in class, it's a base template parametrized on the derived class, a classical CRTP. Mix-ins are classes that inherit from a template parameter. I.e. template <typename Base> class Mixin : public Base { }; My personal opinion is that mix-ins are a great tool for certain circumstances. I don't think that violate Liskov's principle, rather they "templatize" the subclass. I.e., every concrete Mixin IS-A a specific Base. BTW, a couple of years ago Andrei Alexandrescu wrote a paper with Emery Berger that described a policy-based memory allocation technique that heavily relied on mix-ins. [excess quoting deleted--mod] Andy. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Alf P. Steinbach /Usenet on 6 Jul 2010 11:22 * DeMarcus, on 06.07.2010 21:15: > As I understand, Policies have been widely accepted, but is it the same > with Mixins? Or does people still believe Mixin is a bad way to avoid > Liskov's IS-A principle? I can't think of any good ways to avoid the LSP (Liskov Substitution Principle). Whether it's done by a mixin or in some other way, it's generally bad. Better to strive to honor the LSP. > My latest Mixin looks like this. > > template<class T> > class CopyMixin > { > public: > typedef std::shared_ptr<T> SPtr; > > SPtr copy() const > { > // Use NVI. > return copy_(); > } > > protected: > virtual SPtr copy_() const = 0; > > }; > > > class SomeClass : public CopyMixin<SomeClass> > { > private: > virtual SPtr copy_() const > { > SPtr c = /* Make a proper deep copy. */ > return c; > } > }; Usually your "copy" is called "clone", it's like a de facto convention in C++. The C++ FAQ for some reason regards it as a special case of "virtual construction" (the FAQ is the only place I've seen that term used for that). E.g., while clone() is typically implemented in terms of the copy constructor, one can imagine a newInstance() implemented in terms of the default constructor. > What do you think about Mixins in general? No strong feelings either way. > And if you have time, what do you think about above CopyMixin? I think it's nice as an exercise, i.e. for learning about mixins, but it doesn't solve any of the following three problems of cloning in C++: * Checking that cloning is properly implemented. With the above it's difficult to assert anything about the clone_() result, since if an override of clone_() is missing in some class, then that missing override can not assert that it's missing. * Providing a covariant result. With the above the copy() result is always shared_ptr<TopMostBase>. * Avoiding source code repetition of the clone implementation. With the above every class must, redundantly, implement copy_(). > (Maybe a better copy mixin is already invented. If you know of any, > please show me.) The best I've come up with for cloning is a macro. I discuss that and two other techniques that solve the three problems above, at <url: http://alfps.wordpress.com/2010/06/12/cppx-3-ways-to-mix-in-a-generic-cloning-implementation/>. I think you'll agree with me that of the three approaches (macro, middle-man base class and sideways inheritance with dominance in virtual inheritance) the macro wins in simplicity of usage and grokkability of implementation. :-) But perhaps there is some fourth and even fifth way. I wouldn't be surprised if e.g. Andrei Alexandrescu managed devise something that beats the macro. Cheers & hth., - Alf -- blog at <url: http://alfps.wordpress.com> [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Ulrich Eckhardt on 6 Jul 2010 21:15
DeMarcus wrote: > As I understand, Policies have been widely accepted, but is it the same > with Mixins? Policies or traits are harder to understand than mixins, IMHO. Other than that, yes, mixins are a good way to separate a single feature out into a separate class that can be debugged, reused and understood on its own. > Or does people still believe Mixin is a bad way to avoid > Liskov's IS-A principle? I wouldn't understand a mixin as a baseclass, as its its own functionality is usually limited. To me, it's rather a feature that is attached to a class and which is written as a baseclass in C++. In Python you might use a decorator for that instead, e.g. there is one in Python that can construct all comparison operators for a class from just the less-than comparison. > template<class T> > class CopyMixin > { > public: > typedef std::shared_ptr<T> SPtr; > > SPtr copy() const > { > // Use NVI. > return copy_(); > } > protected: > virtual SPtr copy_() const = 0; > }; > > class SomeClass : public CopyMixin<SomeClass> > { > private: > virtual SPtr copy_() const > { > SPtr c = /* Make a proper deep copy. */ > return c; > } > }; [...] > And if you have time, what do you think about above CopyMixin? class base { // Note: never returns null virtual base* do_clone() const = 0; // throw(std::exception) public: std::auto_ptr<base> clone() const // throw(std::exception) { base* p = do_clone(); // must not be null assert(p); // must have the same dynamic type assert(typeid(*p) == typeid(*this)); return std::auto_ptr<base>(p); } }; class derived: public base { virtual derived* do_clone() const { return new derived(*this); } public: std::auto_ptr<base> clone() const // throw(std::exception) { base* p = do_clone(); // must not be null assert(p); // must have the same dynamic type assert(typeid(*p) == typeid(*this)); return std::auto_ptr<base>(p); } } Notes: - I did not factor this out into a mixin but just showed the "normal" implementation for easier reading. - I now see who I'm sharing the object with: nobody. I have exclusive ownership due to auto_ptr. - Check derived class' implementation, both the pointer value and what it points to as far as possible. - Use covariant return types so that you can get the right type if you know that you have a "derived" instance. If you are happy without the covariant return types, you can just go and transform "base" into a mixin and implement do_clone() manually for all derived classes. Otherwise, you might need two mixins, one being the equivalent to "base" and the other to "derived". However, then you get a few complications because one base's pure virtual functions can't be implemented by inheriting another, you have to get the second baseclass in between your real base class instead. Something like this: template<typename T> class abstract_clonable {...}; template<typename T, typename B> class clonable: public B {...}; class base: public abstract_clonable<base> {...}; class derived: public clonable<derived, base> {...}; In other words, you have the following order in which classes inherit from each other: abstract_clonable<base> - declare clonable interface for base base - user-defined content clonable<derived, base> - implement clonable for derived derived - user-defined content Uli -- Sator Laser GmbH Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932 [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |