500: Document stc_find_exact and stc::itself in Static tour

https://svn.lrde.epita.fr/svn/oln/trunk/static ChangeLog | 9 ++ tests/tour.cc | 257 +++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 173 insertions(+), 93 deletions(-) Index: ChangeLog from Roland Levillain <roland@lrde.epita.fr> Document stc_find_exact and stc::itself in Static tour. * tests/tour.cc (dynamic_hierarchy, simple_static_hierarchy): (static_hierarchy_with_methods): Aesthetic changes. (static_hierarchy_with_any): Rephrase comments. (static_hierarchy_with_a_non_leaf_concrete_class): New section. Index: tests/tour.cc --- tests/tour.cc (révision 499) +++ tests/tour.cc (révision 500) @@ -29,6 +29,7 @@ /// \brief A tour of Static and SCOOP features. # include <stc/any.hh> +# include <stc/find_exact.hh> // FIXME: ``Fil rouge'': building a small (but complete) static // hierarchy, using all features from Static. Possibly, this @@ -40,9 +41,7 @@ // having introduced the vtypes. // FIXME: Things to show: -// - any // - exact -// - find_exact // - super // - virtual types (and macros for super) // - multiple super @@ -58,46 +57,36 @@ | A small dynamic hierarchy. | `----------------------------*/ -// Normally, we'd be writing something like this: +/* Our first step in this tour will be the definition of a static + library. In classic (dynamic) OO programming, our example would + look like this: */ namespace dynamic_hierarchy { - // A is abstract. + // `A' is an abstract class. struct A { // A virtual method. - virtual void foo() - { - // ... - } + virtual void foo() { /* ... */ } // A virtual pure method. virtual void bar() = 0; }; - // B is abstract. + // `B' is a concrete class. struct B { // A redefined method. - virtual void foo() - { - // ... - } - // B::bar is defined. - virtual void bar() - { - // ... - } + virtual void foo() { /* ... */ } + // `B::bar' is defined. + virtual void bar() { /* ... */ } }; - // C is concrete + // `C' is a concrete class. struct C { - // A redefined method. - virtual void foo() - { - // ... - } + // `B::foo' is redefined. + virtual void foo() { /* ... */ } }; } // end of namespace dynamic_hierarchy @@ -107,16 +96,16 @@ | A small static hierarchy. | `---------------------------*/ -// Let's start building a small static hierarchy. Converting the first -// dynamic hierarchy results in: - -// FIXME: Comments. +/* Let's start building a small static hierarchy similar to the above + dynamic hierarchy. */ namespace simple_static_hierarchy { /* In traditional OO design, a object has two types : + - a static type, known at compile time; - a dynamic type or exact type, known at run time. + The dynamic type is more precise (or equally precise) than the static type: it's a subclass of the static type. @@ -128,20 +117,22 @@ In the Static C++ Object-Oriented Paradigm (SCOOP), an object still has two types, but they are both static: + - the current type, which can be be an abstraction type; - the exact type. + As everything is static, SCOOP must rely on the static type system of C++, i.e, the current type must hold the information of the exact type. This is achieved through the use of templates: a current type embeds the exact type as a template parameter. Consequently, in SCOOP all derivable classes of a hierarchy are - turned into templates and have an ``Exact'' parameter, which is - the exact static type of the object, à la Curiously Recurring - Template Pattern (CRTP) [1]. + turned into templates and have an `Exact' parameter, which is the + exact static type of the object, à la ``Curiously Recurring + Template Pattern'' (CRTP) [1]. Let's have a look at small example of static inheritance, with - only two classes, A and B. */ + only two classes, `A' and `B'. */ template <typename Exact> struct A @@ -152,64 +143,152 @@ { }; - /* For instance, in the code above, A is turned into a template - class and has an Exact parameter, and B doesn't derive from just - A, but from A<B>. This trick allows us to write: + /* In the above code, `A' is turned into a template class and has an + `Exact' parameter, and `B' doesn't derive from just `A', but from + `A<B>'. This trick allows us to write: A<B>* a = new B; - As you can see, the current type still holds the exact type! In - the next section, we'll see how to actually get back the exact - type. */ + As you can see, the current type still holds the exact type! + Later, we'll see how to actually get back the exact type. */ } // end of namespace simple_static_hierarchy -/*-----------. -| stc::any. | -`-----------*/ + +// ---------- // +// stc::any. // +// ---------- // namespace static_hierarchy_with_any { /* To ease the retrieval of the exact type, we'll make use of - stc::any. This is an instrumentation of the hierarchy to ease + `stc::any'. This is an instrumentation of the hierarchy to ease the retrieval of the exact type and the conversion of the object - to this type. In fact, there is not a single stc::any class, but - several, which have their advantages and drawbacks w.r.t. speed, - memory print and support for diamond inheritance. We'll only deal - with stc::any__simple in this Static tour. - - stc::any is used as the base class of any top class of a static - hierarchy: it is passed the Exact type, just like any non-leaf - class of the hierarchy. */ + to this type. In fact, there is not a single `stc::any' class, + but several, which have their advantages and drawbacks + w.r.t. speed, memory print and support for diamond inheritance. + We'll only deal with `stc::any__simple' in this Static tour: + where you'll see `stc::any', simply read `stc::any__simple'. + + `stc::any' is used as the base class of any top class of a static + hierarchy. It is passed the `Exact' type, just like any non-leaf + class of the hierarchy (a leaf class is a class which is not + derived, i.e., at the bottom of an inheritance tree). */ template <typename Exact> struct A : public stc::any__simple<Exact> { }; - /* Now, let's turn be into a derivable class: we only have to make - it a template class, with an Exact parameter, and let it pass - this exact type to A. */ + /* Now, let's turn `B' be into a derivable class: we only have to + make it a template class, with an `Exact' parameter, and let it + pass this exact type to `A'. */ template <typename Exact> struct B : public A<Exact> { }; - /* We now introduce a concrete leaf class, C, which derives from B, - and passes its own type as exact type. */ + /* We now introduce a concrete leaf class, `C', which derives from + `B', and passes its own type as exact type. */ struct C : public B<C> { }; -} // end of namespace static_hierarchy +} // end of namespace static_hierarchy_with_any -// FIXME: stc/exact.hh. -// FIXME: stc/find_exact.hh and the non-leaf concrete classes. -// -// « Implicitly, our non-leaf classes are abstract. (...) » +// ------------ // +// stc::exact. // +// ------------ // + +// FIXME: To do. + + +// --------------------------- // +// Non-leaf concrete classes. // +// --------------------------- // + +/* All classes carrying an exact type are implicitly abstract classes. + Thus, with our current modeling, non-leaf classes are + compulsorily abstract. This is in compliance with good OO design + practices: in an class hierarchy, non-leaf classes should be + abstract. But what if we wanted (for a reason or another) B to be + a concrete (i.e., instantiable) class? The form `B<>' is not + allowed: a value must be provided for the `Exact' parameter. This is + the role of the stc::itself tag. + + By convention, a class whose exact type is `B<stc::itself>' is + considered concrete. To shorten the coding style, non-leaf + concrete classes take `stc::itself' as default value for their + `Exact' parameter (see below). This way, `B<>' becomes a correct + type. + + The only remaining difficulty is to pass the base class the right + exact type. A small metacode is required here, hidden behind the + `stc_find_exact' helper macro. The code below explains the + necessary changes. */ + +namespace static_hierarchy_with_a_non_leaf_concrete_class +{ + + /* A is left unchanged (it is still an abstract class). */ + + template <typename Exact> + struct A : public stc::any__simple<Exact> + { + }; + + /* B is turned into a concrete class. To achieve this, we apply two + changes: + + 1. the parameter passed to A (B's base class) is no longer + `Exact', but `stc_find_exact(B, Exact)'. The `stc_find_exact' + macro evaluates to `B<>' (i.e., `B<stc::itself>') or to + `Exact', depending on whether `Exact' is equal to + `stc::itself' or not; + + 2. `Exact' takes a default value, `stc::itself', so that one can + abbreviate `B<stc::itself>' to `B<>' (this change is a pure + matter of style and is optional). */ + + template <typename Exact = stc::itself> + struct B : public A< stc_find_exact(B, Exact) > + { + }; + + /* C is left unchanged. */ + + struct C : public B<C> + { + }; + + /* If we loot at the classes above C and B<> in the inheritance + tree, we have: + + A<C> A< B<> > + ^ ^ + | | + B<C> B<> + ^ + | + C + + The exact type is correctly passed to super classes. */ + +} // end of namespace static_hierarchy_with_a_non_leaf_concrete_class + +/* To put it in a nutshell: + + - non-leaf classes are abstract by default in SCOOP; + - to turn a non-leaf class `Foo' into a concrete class, you have to + - pass it `stc_find_exact(Foo, Exact)' instead of `Exact' as + exact type parameter to its super class; + - optionally (but recommended), give its `Exact' parameter a + default value, `stc::itself'; + - to use such a class as a concrete one, simply use it with an empty + `Exact' parameter: `Foo<>'. */ // --------- // @@ -226,48 +305,31 @@ template <typename Exact> struct A : public stc::any__simple<Exact> { - // A static ``virtual'' method. Notice there is no virtual - // keyword: the (static) dispatch is done manually through the - // delegation to impl_foo. - void foo() - { - this->exact().impl_foo(); - } - void impl_foo() - { - // Empty. - } - - // A virtual pure method. - virtual void bar() - { - this->exact().impl_bar(); - } - // No impl_bar, since bar is virtual pure; + /* Facade of a statically-dispatched method. Notice there is no + `virtual' keyword: the (static) dispatch is done manually + through the delegation to impl_foo. */ + void foo() { this->exact().impl_foo(); } + // Implementation of the method. + void impl_foo() { /* ... */ } + + // A ``virtual'' pure (i.e., abstract) method. + void bar() { this->exact().impl_bar(); } + // (No `impl_bar', since bar is abstract.) }; template <typename Exact> - struct B : public A<Exact> - { - // Redefinition. - void impl_foo() - { - // Empty. - } - // Definition. - void impl_bar() + struct B : public A< stc_find_exact(B, Exact) > { - // Implementation goes here. - } + // A redefined method. + void impl_foo() { /* ... */ } + // B::bar (implementation) is defined. + void impl_bar() { /* ... */ } }; struct C : public B<C> { // Redefinition. - void impl_foo() - { - // Empty. - } + void impl_foo() { /* ... */ } }; } // end of namespace static_hierarchy_with_methods @@ -281,3 +343,12 @@ [1] Coplien, James O. (1995, February). "Curiously Recurring Template Patterns". C++ Report: 24-27. */ + + + +/// Local Variables: +/// ispell-local-dictionary: "american" +/// End: + +// LocalWords: inline stc namespace vtypes OO struct CRTP typename metacode +// LocalWords: instantiable impl ispell american
participants (1)
-
Roland Levillain