Re: [boost] Are there any interest in a pimpl library?

----Original Message---- From: Asger Mangaard [mailto:tmb@tmbproductions.com] Sent: 27 September 2005 16:13 To: boost@lists.boost.org Subject: Re: [boost] Are there any interest in a pimpl library?
Could you be more specific as to what functionality such a library would supply? If you already have an implementation then an example of it's use would be interesting.
That was my immediate reaction too.
It is my understanding that the pimpl idiom is fairly simple yet also class specific. I currently implement it like this: [snip classic pimpl idiom]
The only thing my library does is to initialize the forward declared class, using heap or static memory through policies. Also, provides an easy way of accessing the data.
Eg.
.hpp
boost::pimpl<struct CMyData> m_MyData;
.cpp
struct CMyData { CMyData() : m_Integer(0) { } int m_Integer; };
/// Data access m_MyData->m_Integer = 2341;
The CMyData will be initialized the first time its data members are accessed.
That means each use of m_MyData operator ->() has got to check whether the structure is initialized or not, and initialize it if so. Isn't it much easier to initialize the pimpl struct in the constructor of the outer class? I also don't see how much easier it can get to access the data than to write: pimpl->m_Integer -- Martin Bonner Martin.Bonner@Pitechnology.com Pi Technology, Milton Hall, Ely Road, Milton, Cambridge, CB4 6WZ, ENGLAND Tel: +44 (0)1223 441434

----Original Message---- From: Asger Mangaard [mailto:tmb@tmbproductions.com] Sent: 27 September 2005 16:13 To: boost@lists.boost.org Subject: Re: [boost] Are there any interest in a pimpl library?
Could you be more specific as to what functionality such a library would supply? If you already have an implementation then an example of it's use would be interesting.
That was my immediate reaction too.
It is my understanding that the pimpl idiom is fairly simple yet also class specific. I currently implement it like this: [snip classic pimpl idiom]
The only thing my library does is to initialize the forward declared class, using heap or static memory through policies. Also, provides an easy way of accessing the data.
Eg.
.hpp
boost::pimpl<struct CMyData> m_MyData;
.cpp
struct CMyData { CMyData() : m_Integer(0) { } int m_Integer; };
/// Data access m_MyData->m_Integer = 2341;
The CMyData will be initialized the first time its data members are accessed.
That means each use of m_MyData operator ->() has got to check whether the structure is initialized or not, and initialize it if so. Isn't it much easier to initialize the pimpl struct in the constructor of the outer class?
I also don't see how much easier it can get to access the data than to write:
pimpl->m_Integer
The 'already initialized' check is optimal through a policy. The main advantages are: * Correct copying of pimpl data members. Eg. .hpp struct STest { STest& operator = (const STest& _copy); boost::pimpl<struct CMyData> m_MyData; }; .cpp STest& STest::operator = (const STest& _copy) { m_MyData = _copy.m_MyData; return *this; } would work, where as the raw way would be something like: .hpp struct STest { STest& operator = (const STest& _copy); struct CMyData* m_MyData; }; .cpp STest& STest::operator = (const STest& _copy) { m_MyData = _copy.m_MyData; return *this; } and would cause the CMyData pointer to be copied around. This is probably the reason to why pimpl idioms are mostly used by singleton-like classes (managers, components, etc.) With this new library one can easily apply the pimpl idiom to all kinds of classes (game objects, etc.) · The new/delete/static calls are handled automatically. Eg. actually no need for a con/destructor. I hope this answers your questions. Regards, Asger Mangaard

From: "Asger Mangaard" <tmb@tmbproductions.com>
From: Martin Bonner <martin.bonner@pitechnology.com> [don't snip attributions to text you quote]
From: Asger Mangaard [mailto:tmb@tmbproductions.com]
The only thing my library does is to initialize the forward declared class, using heap or static memory through policies. Also, provides an
What about pimpl types with non-default constructors? I can see an assignment operator taking an impl *, making your proposed class like a reseatable smart pointer. That would permit the client to construct the impl any way necessary and then just hand it off to your class.
easy way of accessing the data.
.hpp
boost::pimpl<struct CMyData> m_MyData;
No forward declaration on a separate line is helpful, I suppose.
The CMyData will be initialized the first time its data members are accessed.
That means each use of m_MyData operator ->() has got to check whether the structure is initialized or not, and initialize it if so. Isn't it much easier to initialize the pimpl struct in the constructor of the outer class?
The 'already initialized' check is optimal through a policy. The main
I take it you mean that your policy can construct the impl instance when the pimpl is instantiated and then opt to not check in the member selection operator? If so, that should probably be the default mechanism. The policy you describe should be called something like, "lazy_creation."
advantages are:
* Correct copying of pimpl data members. Eg.
That's helpful.
.hpp struct STest { STest& operator = (const STest& _copy);
boost::pimpl<struct CMyData> m_MyData; };
.cpp STest& STest::operator = (const STest& _copy) { m_MyData = _copy.m_MyData; return *this; }
Actually, you'd just let the compiler generate the copy assignment operator in this case, which is quite useful.
would work, where as the raw way would be something like:
.hpp struct STest { STest& operator = (const STest& _copy);
struct CMyData* m_MyData; };
.cpp STest& STest::operator = (const STest& _copy) { m_MyData = _copy.m_MyData; return *this; }
and would cause the CMyData pointer to be copied around.
...so of course you'd manage the memory yourself. This *is* an advantage to your proposal.
This is probably the reason to why pimpl idioms are mostly used by singleton-like classes (managers, components, etc.) With this new library one can easily apply the pimpl idiom to all kinds of classes (game objects, etc.)
I don't limit my use to such types.
· The new/delete/static calls are handled automatically. Eg. actually no need for a con/destructor.
...unless needed by the impl type.
I hope this answers your questions.
It would have been helpful to have listed these things in your original post. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Hi, I'm sorry, but I'm really having a hard time figuring out if you're strickly ironic in your answer or not? Do you like the idea or not? Regards, Asger Mangaard
--===============1344030888==
From: "Asger Mangaard" <tmb@tmbproductions.com>
From: Martin Bonner <martin.bonner@pitechnology.com> [don't snip attributions to text you quote]
From: Asger Mangaard [mailto:tmb@tmbproductions.com]
The only thing my library does is to initialize the forward declared class, using heap or static memory through policies. Also, provides an
What about pimpl types with non-default constructors? I can see an assignment operator taking an impl *, making your proposed class like a reseatable smart pointer. That would permit the client to construct the impl any way necessary and then just hand it off to your class.
easy way of accessing the data.
.hpp
boost::pimpl<struct CMyData> m_MyData;
No forward declaration on a separate line is helpful, I suppose.
The CMyData will be initialized the first time its data members are accessed.
That means each use of m_MyData operator ->() has got to check whether the structure is initialized or not, and initialize it if so. Isn't it much easier to initialize the pimpl struct in the constructor of the outer class?
The 'already initialized' check is optimal through a policy. The main
I take it you mean that your policy can construct the impl instance when the pimpl is instantiated and then opt to not check in the member selection operator? If so, that should probably be the default mechanism. The policy you describe should be called something like, "lazy_creation."
advantages are:
* Correct copying of pimpl data members. Eg.
That's helpful.
.hpp struct STest { STest& operator = (const STest& _copy);
boost::pimpl<struct CMyData> m_MyData; };
.cpp STest& STest::operator = (const STest& _copy) { m_MyData = _copy.m_MyData; return *this; }
Actually, you'd just let the compiler generate the copy assignment operator in this case, which is quite useful.
would work, where as the raw way would be something like:
.hpp struct STest { STest& operator = (const STest& _copy);
struct CMyData* m_MyData; };
.cpp STest& STest::operator = (const STest& _copy) { m_MyData = _copy.m_MyData; return *this; }
and would cause the CMyData pointer to be copied around.
...so of course you'd manage the memory yourself. This *is* an advantage to your proposal.
This is probably the reason to why pimpl idioms are mostly used by singleton-like classes (managers, components, etc.) With this new library one can easily apply the pimpl idiom to all kinds of classes (game objects, etc.)
I don't limit my use to such types.
· The new/delete/static calls are handled automatically. Eg. actually no need for a con/destructor.
...unless needed by the impl type.
I hope this answers your questions.
It would have been helpful to have listed these things in your original post.

From: "Asger Mangaard" <tmb@tmbproductions.com>
I'm sorry, but I'm really having a hard time figuring out if you're strickly ironic in your answer or not?
The only thing remotely ironic in what I wrote was WRT the one-versus-two-line declaration. That is, your scheme avoids a separate line for the declaration of the impl type, and I was noting that it was only marginally better.
Do you like the idea or not?
It seems as if it could be quite useful.
From: "Asger Mangaard" <tmb@tmbproductions.com>
From: Martin Bonner <martin.bonner@pitechnology.com> [don't snip attributions to text you quote]
This wasn't irony. I was being prescriptive.
From: Asger Mangaard [mailto:tmb@tmbproductions.com]
The only thing my library does is to initialize the forward declared class, using heap or static memory through policies. Also, provides an
What about pimpl types with non-default constructors? I can see an assignment operator taking an impl *, making your proposed class like a reseatable smart pointer. That would permit the client to construct the impl any way necessary and then just hand it off to your class.
I'd still like to hear what you have in mind here.
easy way of accessing the data.
.hpp
boost::pimpl<struct CMyData> m_MyData;
No forward declaration on a separate line is helpful, I suppose.
Here's where I was acknowledging a marginal benefit.
The 'already initialized' check is optimal through a policy. The main
I take it you mean that your policy can construct the impl instance when the pimpl is instantiated and then opt to not check in the member selection operator? If so, that should probably be the default mechanism. The policy you describe should be called something like, "lazy_creation."
What do you think of this?
advantages are:
* Correct copying of pimpl data members. Eg.
That's helpful.
That's not irony. I was noting that your approach was helpful on this point.
.hpp struct STest { STest& operator = (const STest& _copy);
struct CMyData* m_MyData; };
.cpp STest& STest::operator = (const STest& _copy) { m_MyData = _copy.m_MyData; return *this; }
and would cause the CMyData pointer to be copied around.
...so of course you'd manage the memory yourself. This *is* an advantage to your proposal.
Clearly, there's no irony here. There was a tiny bit of sarcasm in that few would copy the pointer as shown.
I hope this answers your questions.
It would have been helpful to have listed these things in your original post.
Here I was pointing out that your initial points omitted a great many details that were necessary for us to understand your proposal and took many replies to extract. This, too, was prescriptive so that your future messages will be more helpful up front. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

I'm sorry, but I'm really having a hard time figuring out if you're strickly ironic in your answer or not?
The only thing remotely ironic in what I wrote was WRT the one-versus-two-line declaration. That is, your scheme avoids a separate line for the declaration of the impl type, and I was noting that it was only marginally better.
That I'm glad to hear. I just wanted to make sure.
The only thing my library does is to initialize the forward
class, using heap or static memory through policies. Also,
declared provides an
What about pimpl types with non-default constructors? I can see an assignment operator taking an impl *, making your proposed class like a reseatable smart pointer. That would permit the client to construct the impl any way necessary and then just hand it off to your class.
I'd still like to hear what you have in mind here.
I actually didn't include this in my initial thoughts. Mainly because pimpl classes will most often be small structs. However, I'm certainly very fond of your idea. -I'll include it in my library asap.
The 'already initialized' check is optimal through a policy. The main
I take it you mean that your policy can construct the impl instance when the pimpl is instantiated and then opt to not check in the member selection operator? If so, that should probably be the default mechanism. The policy you describe should be called something like, "lazy_creation."
What do you think of this?
I fully agree, and will implement it asap.
I hope this answers your questions.
It would have been helpful to have listed these things in your original post.
Here I was pointing out that your initial points omitted a great many details that were necessary for us to understand your proposal and took many replies to extract. This, too, was prescriptive so that your future messages will be more helpful up front.
I'm sorry for the lack of information in my initial post, I'll try and correct this in the future. So how does this work? Should I now post my library in the vault for peer reviews, or? Regards, Asger Mangaard

From: "Asger Mangaard" <tmb@tmbproductions.com>
So how does this work? Should I now post my library in the vault for peer reviews, or?
You get to choose how to proceed. You could fully document it and upload what you think is the finished product and see what folks think. Writing documentation is often a terrific way to see whether your design is as nice as you thought. (If it's hard to explain, then there's something wrong unless it is simply a complicated subject.) This offers those interested in your library the benefit of reading documentation rather than reverse engineering usage from the implementation. The disadvantage is you spend time writing a lot of documentation that might need to be rewritten should you have to redesign the library. Another approach is to just upload your code as is and hope someone will look at it, figure out how it works, and provide feedback. The disadvantage is that folks are somewhat less likely to look without documentation explaining it. You can even create some documentation in the form of a README that gives some rudimentary information. In any case, you need to flesh out your design, including finding appropriate use cases and validating your design against them. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

From: "Asger Mangaard" <tmb@tmbproductions.com>
So how does this work? Should I now post my library in the vault for peer reviews, or?
You get to choose how to proceed.
You could fully document it and upload what you think is the finished product and see what folks think. Writing documentation is often a terrific way to see whether your design is as nice as you thought. (If it's hard to explain, then there's something wrong unless it is simply a complicated subject.) This offers those interested in your library the benefit of reading documentation rather than reverse engineering usage from the implementation. The disadvantage is you spend time writing a lot of documentation that might need to be rewritten should you have to redesign the library.
Another approach is to just upload your code as is and hope someone will look at it, figure out how it works, and provide feedback. The disadvantage is that folks are somewhat less likely to look without documentation explaining it.
You can even create some documentation in the form of a README that gives some rudimentary information.
In any case, you need to flesh out your design, including finding appropriate use cases and validating your design against them.
ok, thanks. Regards, Asger Mangaard

I've just uploaded my suggested pimpl library to the file vault, in the root. Suggestions are appreciated. Regards, Asger Mangaard

On 10/3/05, Asger Mangaard <tmb@tmbproductions.com> wrote:
I've just uploaded my suggested pimpl library to the file vault, in the root. Suggestions are appreciated.
I don't really see how this implements the pimpl idiom. There is no method forwarding in the wrapper class, so In order for users to invoke methods, the pimpl's interface must be publicly exposed. This seems to me to run contrary to the enitre reason for pimpls in the first place. It looks like more of a singleton/creation policy implementation than anything else. -- Caleb Epstein caleb dot epstein at gmail dot com

Caleb Epstein wrote: I don't really see how this implements the pimpl idiom. There is no method forwarding in the wrapper class, so In order for users to invoke methods, the pimpl's interface must be publicly exposed. This seems to me to run contrary to the enitre reason for pimpls in the first place.
The pimpl idiom hides the implementation of a given class/struct and all including members from your hpp file. This decreases the compile times greatly. It then relies on the actual implementation to be inside the cpp file. Just like in the 'testsuite' example that's included with the zip file. Isn't this excatly what the pimpl idiom does? Regards, Asger Mangaard

On 10/4/05, Asger Mangaard <tmb@tmbproductions.com> wrote:
The pimpl idiom hides the implementation of a given class/struct and all including members from your hpp file. This decreases the compile times greatly. It then relies on the actual implementation to be inside the cpp file. Just like in the 'testsuite' example that's included with the zip file.
My understanding is that the class that holds the pimpl (lets call it the Interface class) generally provides forwarding methods that invoke methods on an Implementation class (the class pointed to by m_pImpl). From what I can see of your implementation, if a user wants to invoke Implementation::foo, they will need to include Implementation.h, which effectively negates the benefit of pimpl in the first place. I'd call what you've provided a "Pimpl *Holder*", and not a Generic Pimpl (which I don't think can be implemented anyway). -- Caleb Epstein caleb dot epstein at gmail dot com

Caleb Epstein wrote: My understanding is that the class that holds the pimpl (lets call it the Interface class) generally provides forwarding methods that invoke methods on an Implementation class (the class pointed to by m_pImpl). From what I can see of your implementation, if a user wants to invoke Implementation::foo, they will need to include Implementation.h, which effectively negates the benefit of pimpl in the first place.
I really don't understand this, sorry. First, is a method a function/variable/both? Also, could you show the above using code instead of words? That's easier to read I think.
I'd call what you've provided a "Pimpl *Holder*", and not a Generic Pimpl (which I don't think can be implemented anyway).
I certainly do not agree. This is a generic pimpl implementation. Regards, Asger Mangaard

From: Caleb Epstein <caleb.epstein@gmail.com>
On 10/4/05, Asger Mangaard <tmb@tmbproductions.com> wrote:
My understanding is that the class that holds the pimpl (lets call it the Interface class) generally provides forwarding methods that invoke methods on an Implementation class (the class pointed to by m_pImpl). From what I can see of your implementation, if a user wants to invoke Implementation::foo, they will need to include Implementation.h, which effectively negates the benefit of pimpl in the first place.
For pimpl to work, the implementation class must be complete when you try to use it. No library can eliminate that. The pimple library automates the memory management, including during copying and copy assignment, so you don't have to. Thus, you declare a pimpl object and, in the process, forward declare your impl type, and in exchange, you get automated memory management. Where's the problem? -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

On 10/4/05, Rob Stewart <stewart@sig.com> wrote:
For pimpl to work, the implementation class must be complete when you try to use it. No library can eliminate that.
Or the Interface class provides methods that forward to the Implementation class. The pimple library automates the memory management, including
during copying and copy assignment, so you don't have to. Thus, you declare a pimpl object and, in the process, forward declare your impl type, and in exchange, you get automated memory management. Where's the problem?
I guess my problem is one of terminology. In my mind, a Pimpl class holds the pointer to the Implementation as well as providing the methods that forward to the Implementation. This implementation only holds the pointer and manages the memory, which makes me think it should be called a PimplHolder, and not a Pimpl. Digressingly yours, -- Caleb Epstein caleb dot epstein at gmail dot com

From: Caleb Epstein <caleb.epstein@gmail.com>
On 10/4/05, Rob Stewart <stewart@sig.com> wrote:
For pimpl to work, the implementation class must be complete when you try to use it. No library can eliminate that.
Or the Interface class provides methods that forward to the Implementation class.
Those Interface class member functions *use* the implementation class. The implementation class must be complete for those member functions, which is what I wrote. The usual structure is forward declaration in the header and then definition and use in the implementation file.
I guess my problem is one of terminology. In my mind, a Pimpl class holds the pointer to the Implementation as well as providing the methods that forward to the Implementation. This implementation only holds the pointer and manages the memory, which makes me think it should be called a PimplHolder, and not a Pimpl.
There's your problem. A "pimpl" is a pointer to an implementation class instance. "pimpl" can be thought of as a contraction of "pointer to implementation," if you like. It actually arose because many like to name such pointer data members "pImpl" or "pimpl" (often with additional adornments), but then those names came from contracting "pointer to...." Anyway, the class that *has* a pimpl can actually have many, but usually has only one. That class simply uses the pimpl as a means to hide implementation details, often to improve compilation times or to decouple code. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Caleb Epstein wrote: I guess my problem is one of terminology. In my mind, a Pimpl class holds the pointer to the Implementation as well as providing the methods that forward to the Implementation. This implementation only holds the pointer and manages the memory, which makes me think it should be called a PimplHolder, and not a Pimpl.
Are you asking for functions that modify the pimpl's content? Those are not part of the original idiom. What you suggest is merly comfort functions, ones that can still be added manually of course. I just don't see the trouble of accessing the pimpled class through a ptr/ref. Regards, Asger Mangaard

I've just uploaded my suggested pimpl library to the file vault, in the root.
Suggestions are appreciated.
The trouble is pimpl's are normally idioms not libraries (because you have to write all the forwarding functions by hand). If I understand what you're doing here correctly, your pimple class is really just another smart pointer, but with deep copy semantics. John.

The trouble is pimpl's are normally idioms not libraries (because you have to write all the forwarding functions by hand). If I understand what you're doing here correctly, your pimple class is really just another smart pointer, but with deep copy semantics.
These smart_ptr/policy_ptr variations appear all the time. I've decided to just ignore them. People should be able to find PBSP themselves and know that it's all just another policy. Gennadiy

Gennadiy wrote: These smart_ptr/policy_ptr variations appear all the time. I've decided to just ignore them. People should be able to find PBSP themselves and know that it's all just another policy.
What is 'PBSP'? Also, I didn't find any policy_ptr in boost (it would be helpful though)? Regards, Asger Mangaard

"Asger Mangaard" <tmb@tmbproductions.com> wrote in message news:1369.80.167.84.240.1128450627.squirrel@webmail1.b-one.net...
Gennadiy wrote: These smart_ptr/policy_ptr variations appear all the time. I've decided to just ignore them. People should be able to find PBSP themselves and know that it's all just another policy.
What is 'PBSP'?
Policy based smart pointer
Also, I didn't find any policy_ptr in boost (it would be helpful though)?
There is one in review queue Gennadiy

From: "Gennadiy Rozental" <gennadiy.rozental@thomson.com>
These smart_ptr/policy_ptr variations appear all the time. I've decided to just ignore them. People should be able to find PBSP themselves and know that it's all just another policy.
Is this a backhanded way of saying, "you're wasting your time because we'll have a PBSP soon and it will do everything?" Even if we do get a PBSP sometime soon, it still needs policies to provide the desired behavior. Then, you need some way of packaging it nicely for this purpose. Otherwise, you create an uglier wart that's harder to use. IOW, even with a PBSP, you'd probably want at least a header with the policies and some wrapper class or typedefs to make it easier to use. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

These smart_ptr/policy_ptr variations appear all the time. I've decided to just ignore them. People should be able to find PBSP themselves and know that it's all just another policy.
Is this a backhanded way of saying, "you're wasting your time because we'll have a PBSP soon and it will do everything?" Even
You got it.
if we do get a PBSP sometime soon, it still needs policies to provide the desired behavior. Then, you need some way of packaging it nicely for this purpose. Otherwise, you create an uglier wart that's harder to use. IOW, even with a PBSP, you'd probably want at least a header with the policies and some wrapper class or typedefs to make it easier to use.
Yes. Policy implementation and convenience typedef is my choice for the solution IMO. Gennadiy

Gennadiy wrote:
if we do get a PBSP sometime soon, it still needs policies to provide the desired behavior. Then, you need some way of packaging it nicely for this purpose. Otherwise, you create an uglier wart that's harder to use. IOW, even with a PBSP, you'd probably want at least a header with the policies and some wrapper class or typedefs to make it easier to use.
Yes. Policy implementation and convenience typedef is my choice for the solution IMO.
I'll gladly implement this policy if/when we get a policy_ptr. Until then, I definately think the pimpl library is the way to go. Regards, Asger Mangaard

I'll gladly implement this policy if/when we get a policy_ptr. Until then, I definately think the pimpl library is the way to go.
Way to go where? I don't see it as another variation of smatr_ptr within boost. As your own library - of course. Gennadiy

From: "Gennadiy Rozental" <gennadiy.rozental@thomson.com>
I'll gladly implement this policy if/when we get a policy_ptr. Until then, I definately think the pimpl library is the way to go.
Way to go where? I don't see it as another variation of smatr_ptr within boost. As your own library - of course.
If one is looking for a pimpl library one won't look at the smart_ptr library until and unless one recognizes that it is a type of smart pointer. Thus, a separate library, even if implemented using the smart_ptr library, would be helpful. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

John wrote: The trouble is pimpl's are normally idioms not libraries (because you have to write all the forwarding functions by hand). If I understand what you're doing here correctly, your pimple class is really just another smart pointer, but with deep copy semantics.
It's simple indeed, that's the intention. However, it does provide all advantages of the original idiom, plus more (automatically memory management, copy-by-value, most often no need for con/destructors). I know that have helped me a lot, that's why I'm suggestion its inclusion in boost. Regards, Asger Mangaard
participants (7)
-
Asger Mangaard
-
Caleb Epstein
-
Chris Uzdavinis
-
Gennadiy Rozental
-
John Maddock
-
Martin Bonner
-
Rob Stewart