Boost logo

Boost :

From: Mat Marcus (mmarcus_at_[hidden])
Date: 2002-02-22 12:38:24


I would really like to see us further explore GenVoca layered designs. I
didn't think there was much chance of this after the limited response to
<http://groups.yahoo.com/group/boost/message/23654>. This stuff is hard to
explain, but maybe by taking it in smaller pieces we can establish a useful
dialog. So, rather than another lengthy post on the subject, I'll try to
stimulate discussion by diving into a couple of small specifics.

I see two main differences between C&E-style GenVoca and policy based
design:

Policy based design (PBD)
  * PBD uses Policies in two simultaneous roles, implemetation class
templates and as a configuration DSL.
  * PBD favors policies which don't communicate; collaboration is
orchestrated by a "manager" class template (e.g. SmartPtr)

GenVoca
  * GenVoca uses layers (generalized policies) for the implementation class
templates. A separate configuration generator is used to parse the
configuration DSL
  * GenVoca offers (but does not require) the possiblity of communication
between layers

There is an appealing simplicity in PBD: no configuration generator is
required. However, for some domains, the flexibility and reusabiity offered
by GenVoca probably outweighs the cost of the additional required
machinery. Of course, if you plan on writing a configuration generator
anyway then I see no advantage to using policies instead of layers; in this
case policies are merely the degenerate case of a zero-layered design.
Perhaps an example from the aformentioned post would help clarify.

Example (from the aformentioned post)

I will examine a feature model/configuration DSL reverse engineered from
Andrei's SmartPtr. Then I will indicate how the policy based design might
map to a (degenerate) single layered GenVoca design. In this case the
configuration generator, omitted until sufficient interest, is quite
trivial, as the DSL and the ICCL are more or less identical. Things only
get interesting when we try to coax out the appropriate communicating
layers. See the above post for a little more detail.

 Front End/Feature Model/Configuration DSL

   SmartPtr : SmartPtr [ElementType,
                                          OwnershipPolicy,
                                          ConversionPolicy,
                                          CheckingPolicy,
                                          StoragePolicy]
    ElementType : T

    OwnershipPolicy : RefCounted | RefCountedMT
                               | ComRefCounted | RefLinked
                               | DeepCopy
                               | DestructiveCopy | NoCopy

    ConversionPolicy : AllowConversion
                               | DisallowConversion

    CheckingPolicy : AssertCheck
                               | AssertCheckStrict
                               | NoCheck
                               | RejectNullStatic
                               | RejectNull
                               | RejectNullStrict

    StoragePolicy : DefaultSPStorage

We can use this feature model as the configuration DSL. Orthogonality is
natural on the front end.

Back End/Single Layered Genvoca Grammar/ICCL

    SmartPtr : SmartPtr[Config]

Config
    ElementType : T

    OwnershipPolicy : RefCounted | RefCountedMT
                               | ComRefCounted | RefLinked
                               | DeepCopy
                               | DestructiveCopy | NoCopy

    ConversionPolicy : AllowConversion
                               | DisallowConversion

    CheckingPolicy : AssertCheck
                               | AssertCheckStrict
                               | NoCheck
                               | RejectNullStatic
                               | RejectNull
                               | RejectNullStrict

    StoragePolicy : DefaultSPStorage

or in C++:

struct MyRefCountedConvertibleAssertCheckFooPtrConfig // simplistic: no
layering or communication
{
    typedef OwnershipPolicy RefCounted;
    typedef ConversionPolicy AllowConversion;
    typedef CheckingPolicy AssertCheck;
    typedef StoragePolicy DefaultSPStorage;
    typedef Foo ElementType;
};

template <class Config>
class SmartPtr : public Config
{
 // ...
};

of course the client will not want to declare

   SmartPtr<MyRefCountedConvertibleAssertCheckFooPtrConfig>

instead GenVoca uses a configuration generator and DSL so client code will
look like

    typename SmartPtrGenerator<T, ref_counted,
                default_storage, assert_checking,
                disallow_conversion>::type;

(Aside: typedef templates would be nice here). The implementation of such a
SmartPtrGenerator on top of our SmartPtr ICCL is straightforward, using
standard metaprogramming techniques and I will leave it for another article
if there is any interest. Or see for example C&E page 587 and page 654.

These explanations and examples are intentionally incomplete. But if there
is any interest I'd be happy to explore this stuff in more detail --
questions, comments or corrections are very welcome.

Mat

#####
    Beman> --- In boost_at_y..., Beman Dawes <bdawes_at_a...> wrote: Tim,
    Beman>
    Beman> You might also read Mat Marcus'
    Beman> http://groups.yahoo.com/group/boost/message/23654 if you
    Beman> haven't done so already.
    Beman>
    Beman> The techniques you, Dave, Jeremy, and Mat are exploring are
    Beman> on the research frontier of generic and generative
    Beman> programming. Very few people understand them fully. I
    Beman> know I don't.
    Beman>
    Beman> For these techniques to migrate into the main stream, there
    Beman> is a real need for descriptive material that is easier to
    Beman> understand. Andrei Alexandrescu did a great job in his
    Beman> book at making policies easy enough to understand that many
    Beman> of us could start using them in everyday programming.
    Beman> Someone needs to do something similar for combining
    Beman> generative programming, named template parameters, and
    Beman> policy-based design into a unified, understandable,
    Beman> technique.
    Beman>
    Beman> --Beman

    Tim> Thanks for the insight. I have read Mat's post, and if his
    Tim> experience was anything like mine, I found GenVoca to be
    Tim> rather cumbersome. It wasn't clear to me how to divide the
    Tim> architectural layers. That difficulty is partly why I've
    Tim> explored using policy- based design as a "back-end" to a
    Tim> generator, rather than something like GenVoca. Policies are
    Tim> just easier to understand.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk