Boost logo

Boost :

From: David B. Held (dheld_at_[hidden])
Date: 2002-04-30 22:14:43


"David Abrahams" <david.abrahams_at_[hidden]> wrote in message
news:065f01c1f0a6$b081d2a0$6401a8c0_at_boostconsulting.com...
>
> ----- Original Message -----
> From: "David B. Held" <dheld_at_[hidden]>
> >
> > Vertical policies facilitate IPC, but at a cost, depending on the
> > architecture. For instance, Beman made a tradeoff between straight
> > vertical and straight horizontal policy design (diagonal policies?).
> > On the one hand, it simplified the design. On the other hand, it fixed
> > which policies could see each other.
>
> It doesn't have to. You /can/ leave the ordering up to the user. I have
> in mind a "construction kit" where you configure new smart pointers like
> this:

I must be dense, because I don't see how this is at all similar to Beman's
design, in which the Storage policy appears intended to derive from
both Checking and Conversion. The fact that it contained MI, but was
also chained is why I called it a "diagonal" design. It looks like what
you're suggesting is yet another class of designs that I might call a
"ring".

> template <class Value, class Ptr = Value*>
> struct my_ptr
> : smart_ptr<
> com_refcounted<
> always_non_null<
> my_ptr<Value,Ptr> > > >
> {};
>
> Incidentally, this basic approach was suggested to me by Mat Marcus
> at the C++ committee meeting; according to him it's straight GenVoca
> out of C&E.

It looks pretty interesting. I still have a hard time getting my head
around
the idea of something inheriting from itself. However, I can see how
this would be pretty flexible, avoids a template template policy param,
eliminates an explicit pointee type param (in the policies and the
smart_ptr type), and gives all the policies access to the base types, all
in one fell swoop. Of course, it never would have occurred to me that
deriving from a smart pointer type instead of instantiating it would yield
such benefits; but I guess it's just another example of solving a problem
by adding a layer of indirection, eh? I suppose I should check out C&E.

> > The cost I noticed in vertical chaining is the presence of
> > constructors. All policies in the chain must provide the same
> > set of c'tor signatures.
>
> Not neccessarily, but I can see how it would work out best that way.

Oh. Just out of curiosity, how could you avoid that, without changing
the design dramatically?

> > This is a bit annoying, as many of them don't use, say, the T* c'tor,
> > but they must provide it anyway.
>
> A small price, IMO.

In mine as well, unless smart_ptr were made to work with, say,
shared_ptr, and you started adding all these conversion c'tors
that started cluttering up the policies considerably.

> > Another issue with vertical policies is that of default policies. I
> > chose the full vertical route both to provide a wider range of
> > implementations for people to look at, and also to help test the
> > idea of complete control over policy implementations by not
> > limiting policy order. This, of course, makes it impossible to
> > specify partial policy defaults.
>
> "Of course?" Please back up a few steps and explain for those
> of us who are less sophic.

I didn't mean to sound like a sophist, but instead of backing up, I
do believe I explained this statement in the following paragraph.
Basically, if your policies can "arrive" in any order, then you can't
just assign default policies to each template parameter, like so:

template <
    class Policy1 = default_policy_A,
    class Policy2 = default_policy_B,
    class Policy3 = default_policy_C,
    class Policy4 = default_policy_D
>
class policy_based_class
: public Policy1<Policy2<Policy3<Policy4> > > >
{ };

Obviously, if I provide a C and D policy, and nothing else, I end
up with two C and two D policies, and no A and B policies.

> > Specifying individual defaults relies on template parameter
> > position, but if any policy could end up in any position, you
> > can't specify a position-dependent default. So you are left
> > with an all-or-nothing policy parameter.
>
> I'm not sure I see this. The approach I have in mind is actually a
> Policy Adapter pattern: the default policy is to dispatch to the
> behavior of the underlying Ptr type.

I'm afraid I don't grok this at all. If you're talking about the
iterator adaptors Policy Adaptor, then I kinda know what you
mean.

> > The only alternative I see to this is a policy mixer
> > that detects missing policies, and provides defaults. This is
> > hardly a five-minute library design job.
>
> Hearty agreement! See the iterator adaptors library for
> examples.

I read what appeared to be the relevant parts of the iterator
adaptors paper, as well as browsed the source code. All of it
mostly made my head swim. :( I see references to "named
template parameters", which I thought were totally different
from a policy adaptor, but when I looked at the implementation,
I saw how you searched through the policy list, which is more
or less what I expected. I guess I never understood how named
template parameters were implemented. Have you considered
rewriting it with MPL (after it's reviewed, of course)? Or would
that be a bad dependency?

It seems to me that a policy adaptor is a fairly generic idea.
Have you considered generalizing it, and making it standalone,
so other policy-based designs can take advantage of it?

Dave


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