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(a)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