Boost logo

Boost :

Subject: Re: [boost] pimpl library proposal
From: Vladimir Batov (vbatov_at_[hidden])
Date: 2010-12-09 04:35:10


Kris,

Thanks for your input. It's much appreciated.

> From: "Krzysztof Czainski" <1czajnik_at_[hidden]>
> ...
> 2. Pimpl should automate construction and destruction of the Impl struct.
> Your pimpl does that, but lacks a way of customization of the copying
> policy.

Have you had a chance to read through the Pimpl documentation? Currently,
the described Pimpl provides two policies -- pointer_semantics and
value_semantics. In the pimpl.hpp code it looks as follows:

template<class T>
struct pimpl
{
    typedef pimpl_base<impl_ptr> value_semantics;
    typedef pimpl_base<boost::shared_ptr> pointer_semantics;
};

More so, nothing is stopping us from extending it with, say, COW semantics:

template<class T>
struct pimpl
{
    typedef pimpl_base<impl_ptr> value_semantics;
    typedef pimpl_base<boost::shared_ptr> pointer_semantics;
    typedef pimpl_base<cow_ptr> cow_semantics;
};

Isn't it "customization of the copying policy"? Or did you mean something
else?

> And perhaps a way of customization of the creating policy, a factory
> of some sort...

I am under impression that I do not quite understand what you mean by
"customization of the creating policy" either. Isn't that quality achieved
by overloaded constructors? If it is so, then the developer provides the set
of overloaded constructors for his/her class. Regardsless of those
constructors Pimpl does not need to be modified.

> 3. The user should have no way of telling if MyClass uses pimpl or not. It
> should be totally transparent.

I find it hard to visualize what you have in mind. Would it be possible to
provide an example where you believe manually-written pimpl-idiom class is
more transparent than a class derived from the proposed pimpl?

> With Your pimpl, MyClass inherits from
> pimpl_base, bringing in a lot of operations: operator*(), operator
> bool_type() and others. They are protected, but they still are there -
> potentially conflicting with operators, that MyClass might be providing
> for
> the user.
> Therefore I'd prefere making pimpl a member over inheriting from
> it.

Well, you omitted concrete examples/explanations clarifying why you prefer
composition over inheritance in this particular case. Consequently, I have
that nagging feeling that you are taking the "prefer composition over
inheritance" a tiny bit too dogmatically. From where I stand I feel that
Pimpl-derived class needs/wants to expose the complete interface of Pimpl
(after all that's why those methods were introduced in Pimpl -- to re-use
them). That indicates inheritance.

In my view Liskov Substitution Principle is a perfect litmus test for
"should I be inheriting from this type?". And in my view Pimpl fits the
bill.

After all, functional inheritance (as opposed to architectural inheritance)
is quite common programming technique.

As for your concern about "a lot of operations" in Pimpl "potentially
conflicting with operators" of YourClass, then my reading of the
specification is somewhat different. Namely, as I understand, a method
introduced in the derived class makes *all* the methods with the same name
(not just the same signature) in the base class inaccessible.

> 4. Customizability of pimpl: the implementer might want one of different
> approaches to copying: a) disallow, b) share, c) clone, d) others like
> COW.
> I'm not sure which of these Your pimpl provides. I would recommend a
> template parameter to choose a policy. It might be just a smart pointer
> owning the Impl object.

I hope I covered that while answering your #2 point.

> 5. Pimpl should not do more, then there is to the pimpl idiom. That is, it
> should hide the implementation. But it should not implement features like
> operator !=, when the implementer might not want those.

Again, I feel you should have another closer look at the suggested
implementation... because the proposed Pimpl implements (or not)
operator==() based on the supplied policy. Namely, I do not see why a
pointer_semantics-based Pimpl should not provide op==() automatically (as
shared_ptr does). On the other hand, the user has to provide op==() for a
value_semantics-based Pimpl.

> Or it should not implement the possibility of a null object -
> boost::optional is for that.

Well, my view on the usefullness of pimpl::null() happens to be quite
different. In fact, that pimpl::null is there because I use it a *lot*.
Pimpl belongs to a smart-pointer-pattern family and shared_ptr and the likes
provide such functionality (in a somewhat obscure form of shared_ptr() IMHO
of cource).

> 6. You write about pimpl and dynamic polymorphism. I think pimpl should
> have
> nothing to do with polymorphism. Any polymorphic part of a class, even a
> private virtual function, isn't truly private, so it shouldn't be in
> pimpl.
> And everything that is in a pimpl should be truly hidden, even from the
> derived classes.

Well, "pimpl should have nothing to do with polymorphism" is quite a
determined statement. ;-) That mentioned functionality has its purpose -- it
implements Non-Virtual Interface Idiom. If you have no need for that, that's
OK. We should not be denying it to others, should we? In fact, I happen to
use it to fight the complexities of architectural inheritance (where it's
unavoidable).

Best,
V.


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