Boost logo

Boost :

Subject: Re: [boost] pimpl library proposal
From: Vladimir Batov (vbatov_at_[hidden])
Date: 2010-12-14 05:14:39


> From: "Krzysztof Czainski" <1czajnik_at_[hidden]>
> Sent: Friday, December 10, 2010 12:06 AM
> ...
>> 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?
>
> I see. But if I understand correctly, for each smart pointer type, there
> needs to be a specialization of pimpl_base written from scratch.

I am not sure where you've got that impression from. There is one pimpl_base
implementation. Pointer- or value-semantics behavior are defined by the
provided policy class. Pls see the declaration above.

> Now suppose pimpl_base<SmartPtr> does accept any smart pointer:
> scoped_ptr,
> shared_ptr, clone_ptr, cow_ptr, etc... This is where the creation policy
> is
> needed. See below...

I do not immediately see value in Pimpl accepting "any smart pointer" which
are policy classes for Pimpl. In fact, I do not know of any policy-based
class which would accept *any* other class as its policy. I am convinced a
class to be used as a policy by another class must conform to a certain
interface.

> ...
>> 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.
>
> The default creation policy would be to create impl on the heap using
> operator new, and passing the resulting pointer to SmartPtr. But for
> example, when using shared_ptr, it might be a good idea to use a)
> make_shared instead of operator new, b) a custom allocator/deleter.

I am under impression that the functionality you are suggesting is already
available. Namely, (unless I am still missing your point) "make_shared"
quality is provided by boost::shared_ptr itself and nothing more needs to be
done. As for "custom allocator/deleter" or any other creation policy, then
that functionality belongs in the "implementation" class and deployed via
Pimpl interface. So, it seems nothing more needs to be done in Pimpl either.

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

I happen to disagree. Pimpl implements a certain pattern/idiom which has
certain qualities. The user deploying that pattern/idiom expects those
qualities. After all, that's why he/she is deploying that pattern/idiom in
the first place. I do not immediately see benefits of hiding those
qualities.

> Well, I understand You expose the operator bool_type for example.

Again, I believe it is part of the idiom. For example, boost::shared_ptr is
similar in that regard.

> But that is not all. I believe a user is also someone deriving form
> MyClass.
> Your pimpl takes part in runtime polymprphism, and for that it must be
> visible by derived classes.

Again, Pimpl is implementation of a certain programming technique.
Consequently, one can certainly inherit from a Pimpl (and I do it a lot) but
without negating Pimpl's property and ultimately the object size. It's done
via the Bridge pattern (as in GoF). Essentially, the developer has two
separate inheritance hierarchies -- for interface and for implementation. I
believe I have it covered in the documentation.

> ...
> I just thought that, since the user should not know of pimpl's existence,
> there should be no functions to inherit from it.

I see no value in encapsulation for the sake of encapsulation. Say, you can
"typedef boost::shared_ptr<Foo> Zoo;" or go further trying to hide the fact
that Zoo is, in fact, a shared_ptr and, consequently behaves as a
shared_ptr. By trying to hide that fact I believe you do the user great
disservice as you deny the user the knowledge that Zoo has certain
qualities/properties (namely, shared_ptr properties) as *must* be treated as
such.

> ...
>> 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.
>
> True. So, what if the implementer adds operators * and -> to MyClass?
> Accessing pimpl is still possible, but not as convenient any more.
> satic_cast<implementation&>(*this)->... or an extra local reference is
> always needed:

Therefore, if I understand you correctly you are suggesting to remove those
operators altogether, right? ;-) More so, there is no need for the user to
add operators * and -> as Pimpl provides already those operators for
him/her.

> For the pointer_semantics-based Pimpl: I do not think that MyClass should
> have pointer semantics just because its pimpl has pointer semantics. So I
> am
> against forwarding op== from the underlying shared_ptr.

I am not sure I follow -- you deploy pointer-semantics Pimpl but do not want
it to behave as such. I have that feeling you are trying to make things
harder than they need be. In my simple world, if I deploy a fork, I do want
it to "behave" as a fork, i.e. to expose fork-like properties. If I don't,
I'll deploy something else.

> I just think virtual functions should just stay in MyClass, and not go
> into
> pimpl, because they should not be hidden. That is why I think "pimpl
> should
> have nothing to do with polymorphism" ;-)

I do not believe the proposed Pimpl implementation has any virtual
functions. As described in the documentation it's deployed in the
inheritance hierarchies differently (the Bridge pattern in GoF).

> For an example of how I use pimpl, and my pimpl helper, which I called
> value_ptr, I shall quote my earlier post, adding an example of how some
> member function of MyClass might be implemented in terms of pimpl:

I am sure your Pimpl implementation does everything just the way you want
it. :-) And if that works better for you than an already available
component, then I do not see anything wrong with deploying it. I do the same
all the time. ;-) Still, I suspect if you try deploying your no-frills
version of a larger scale, it'll start looking more and more as the proposed
Pimpl. There are countless examples of that behavioral pattern (Java comes
to mind). As for the proposed Pimpl, let me assure you that the
functionality provided and described there is there for a reason. May I
suggest you have another look at the documentation for the proposed Pimpl?
You might come to appreciate its versatility... or might not. :-)

Good luck and all the best in your endeavors,
V.


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