150 likes | 252 Views
An anomaly of subtype relations at component refinement and a generative solution in C++. Zoltán Porkoláb, István Zólyomi. Eötvös Loránd University , Budapest, Hungary. {gsd | scamel}@elte.hu. Example (Harold Ossher). OpEval. OpCheck. OpDisplay. Operator. PlusEval. PlusCheck.
E N D
An anomaly of subtype relations at component refinement and a generative solution in C++ Zoltán Porkoláb, István Zólyomi Eötvös Loránd University, Budapest, Hungary {gsd | scamel}@elte.hu
Example (Harold Ossher) OpEval OpCheck OpDisplay Operator PlusEval PlusCheck PlusDisplay Plus
Possible solutions • Virtual inheritance • Intrusive: specified in base classes • More concerns implies exponential number of virtual bases • Traits • No subtype relationship using hierarchies in traits • AOP • are extensions to standard C++ • Signature • Promising, but non-standard, available only for Gnu compiler • Eiffel: ADOPT • CSet: subtype relationship implemented with metaprogramming • Non-intrusive solution based on the C++ standard
C++ Templates • Macro-like type parameters • Strong type checking • Templates alone form a Turing-complete functional language inside C++ • Based on template specializations • Metaprograms • Executed during compilation • A program can observe its state • May make decisions depending on state • Compile-time adaptation
Source code of Cset construction template <class List> struct CSet; template <class Head, class Tail> struct CSet< Typelist<Head,Tail> > : public Head, public CSet<Tail> { // --- Type name shortcuts typedef CSet<Tail> Rest; typedef CSet< Typelist<Head,Tail> > MyType; // --- Copy constructor CSet(const MyType& mt) : Head(mt), Rest(mt) {} // --- "Recursive" constructor CSet(const Head& head, const Rest& rest): Head(head), Rest(rest) {} }; template <class Head> struct CSet< Typelist<Head,NullType> > : public Head { // --- All in one constructor CSet(const Head& head) : Head(head) {} };
Conversions between CSets • Initialize the head class for each recursion step • Template constructors provide conversion steps (the same for operator=) template <class Head, class Tail> template <class FromType> CSet< Typelist<Head,Tail> > :: CSet(const FromType& f): Head(f), CSet<Tail>(f) {} • Example of usage: CSET_3(PlusEval,PlusDisplay, PlusCheck) sum; CSET_2(OpEval,OpCheck) calculate; calculate = sum;
Advantages • Type safe: based on builtin language conversions • Efficient: no temporal CSets or objects are used, objects are initialized directly • Open: not restricted to CSet only, any user object can be converted without explicit conversion call. struct Minus: public MinusEval, public MinusDisplay, public MinusCheck {}; Minus subtract; calculate = subtract;
Smart pointers • Problems: • Conversion copies objects by value (slicing) • No dynamic binding • Solution: smart pointers • Implementation and usage similar to those of CSet CSET_3(PlusDisplay, PlusEval, PlusCheck) sum; CSETPTR_2(OpDisplay, OpEval) opPtr(sum); // --- Function call with explicit cast static_cast<OpDisplay*>(opPtr)->show(); // --- In longer form with implicit cast OpDisplay *displayPtr = opPtr; displayPtr->show();
CSETPTR_1(OpEval) OpEval *head CSETPTR_2(OpDisplay,OpEval) OpDisplay *head CSETPTR_2(OpDisplay, OpEval) opPtr; points to head: OpDisplay* head: OpEval* points to PlusDisplay PlusCheck PlusEval
CSetRef • Similar to CSetPtr • Store references instead of pointers • Consequences: • A CSetRef object must be initialized • Initializes by reference but copies by value during assignment CSET_3(PlusDisplay, PlusEval, PlusCheck) sum; // --- Initializes by reference CSETREF_3(OpDisplay, OpEval, OpCheck) exprRef(sum); // --- Copies by value exprRef = sum;
#include <iostream> #include “cset.h" struct Shape { virtual void f() { std::cout <<"Shape"; } }; struct Circle : public Shape { void f() { std::cout <<"Circle"; } }; struct Colored {}; struct Filled {}; void main() { CSET_3(Circle,Colored, Filled) extCircle; CSET_3(Colored, Filled, Shape)extShape(extCircle); CSET_2(Filled, Colored)extensions(extCircle); extensions = extShape = extCircle; CSETPTR_3(Colored, Filled, Shape)extShapePtr(extCircle); Shape* shapePtr = extShapePtr; shapePtr->f(); // --- Prints “Circle” CSETPTR_3(Filled, Colored, Circle)extCirclePtr(extCircle); extShapePtr = extCircle; // --- Object -> Pointer extShapePtr = extCirclePtr; // --- Der. Pointer -> Base Pointer extShape = extShapePtr; // --- Pointer -> Object (by value) }
Summary • Support for collaboration based design • Non-intrusive solution • Easy to understand and manage • No extension to standard C++ • Bad experience with compilers vs standards • Features: • Composition of concerns in a single class (CSet) • Conversion between related CSets • Dynamic binding with smart pointers and references
gsd@elte.hu scamel@elte.hu Eötvös Loránd University, Budapest, Hungary Zoltán Porkoláb István Zólyomi Download source from http://gsd.web.elte.hu