[review] Fast track review of Boost.Utility/Singleton begins today

Hi all, Today starts the formal Fast-Track review of the Boost.Utility/Singleton library. This is a very useful utility, so I'm expecting lots of reviews ;) *Description* A Singleton describes a globally accessible and unique facility, typically implemented as a class with inaccessible constructors and a globally accessible function for clients to access a single instance which is created when accessed for the first time. This library provides three Singleton templates that share an identical interface : |- boost::singleton| : can be used to create Singletons with synchronized initialization. If further synchronization is required it has to be implemented by the user. |- boost::mutexed_singleton| : additionally ensures that concurrent access to the instance is mutually exclusive. In other words, only one thread can access the instance at a given time. |- boost::thread_specific_singleton| : instances exist once per thread. *Author* Tobias Schwinger *Download* Get it from here: http://www.boost-consulting.com/vault/index.php?action=downloadfile&filename=singleton.zip&directory=X-Files Read documentation online here: http://torjo.com/tobias/ What to include in Review Comments ================================== Your comments may be brief or lengthy, but basically the Review Manager needs your evaluation of the library. If you identify problems along the way, please note if they are minor, serious, or showstoppers. Here are some questions you might want to answer in your review: * What is your evaluation of the design? * What is your evaluation of the implementation? * What is your evaluation of the documentation? * What is your evaluation of the potential usefulness of the library? * Did you try to use the library? With what compiler? Did you have any problems? * How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? * Are you knowledgeable about the problem domain? And finally, every review should answer this question: * Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion. Best, John Torjo - Review Manager - -- http://John.Torjo.com -- C++ expert ... call me only if you want things done right

John Torjo <john.groups <at> torjo.com> writes:
Today starts the formal Fast-Track review of the Boost.Utility/Singleton library. This is a very useful utility, so I'm expecting lots of reviews ;)
* What is your evaluation of the potential usefulness of the library?
I don't think this is at all useful. People should not be encouraged to use singletons, as there is already a tendency towards overuse. In most circumstances, singletons are a poor design choice, so there is little requirement for their use.
* What is your evaluation of the design? * What is your evaluation of the implementation?
The design mixes several independent issues --- ensuring there is only one instance of a class and avoiding initialization order problems with on-demand initialization for starters. A simple wrapper class that allows for on-demand initialization, would be useful. Conflating that with "there shall be at most one instance" is not. Again, allowing for a preferred destruction sequence of objects with such on-demand initialization might also be useful, but does not belong with the one-instance constraint. thread_specific_singleton is overly complex for what should just amount to a simple use of thread_specific_ptr.
* Did you try to use the library? With what compiler? Did you have any problems?
No, I haven't tried to use it.
* How much effort did you put into your evaluation?
I've read through the code and documentation carefully.
* Are you knowledgeable about the problem domain?
Yes. I've written code that used singletons (and regretted it later), and used code that other people have written containing singletons.
* Do you think the library should be accepted as a Boost library?
No. Anthony

* What is your evaluation of the potential usefulness of the library?
I don't think this is at all useful. People should not be encouraged to use singletons, as there is already a tendency towards overuse. In most circumstances, singletons are a poor design choice, so there is little requirement for their use.
I disagree - singletons are usefull in layered systems (provide an interface to the functionality of the layer). Oliver

On Jan 15, 2008 12:21 PM, Anthony Williams <anthony_w.geo@yahoo.com> wrote:
John Torjo <john.groups <at> torjo.com> writes:
Today starts the formal Fast-Track review of the Boost.Utility/Singleton library. This is a very useful utility, so I'm expecting lots of reviews ;)
* What is your evaluation of the potential usefulness of the library?
I don't think this is at all useful. People should not be encouraged to use singletons, as there is already a tendency towards overuse. In most circumstances, singletons are a poor design choice, so there is little requirement for their use.
I consider singletons just another form of globals and thus bad style. But sometimes they get handy, if you do not want to pass around a context to every function in a module. Anyways, I've regretted too every single singleton that I have used. What about a form of thread local singleton which can be replaced with a scoped construct? //global scope singleton<my_object> my_singleton; void foo() { my_singleton.instance().use_singleton(); // the globaly scoped one or a local replacement. } void bar() { scoped_replacer _ (my_singleton); // replace my_object of baz with a copy my_singleton.instance().perform_local_modification(); foo(); // at this point my_object of baz is reinstantiated } void baz() { scoped_replacer _ (my_singleton, my_object()); // replace the initial my_object // with a copy of the second parameter foo(); // at this point the original my_object is reinstantiated } int main() { baz(); } In practice it is a form of dynamic scoping, which might be more useful and flexible than a static singleton. You definitely want this dynamic scoped object to be per thread. I haven't read Boost.Singleton documentation, maybe it already allows such a functionality. -- gpd

Giovanni Piero Deretta wrote:
On Jan 15, 2008 12:21 PM, Anthony Williams <anthony_w.geo@yahoo.com> wrote:
John Torjo <john.groups <at> torjo.com> writes:
Today starts the formal Fast-Track review of the Boost.Utility/Singleton library. This is a very useful utility, so I'm expecting lots of reviews ;) * What is your evaluation of the potential usefulness of the library? I don't think this is at all useful. People should not be encouraged to use singletons, as there is already a tendency towards overuse. In most circumstances, singletons are a poor design choice, so there is little requirement for their use.
I consider singletons just another form of globals and thus bad style.
Let's see: "I consider if, else, for, do, while and the ternary operator just another form of goto and therefore bad style." ;-)
But sometimes they get handy, if you do not want to pass around a context to every function in a module. Anyways, I've regretted too every single singleton that I have used.
What about a form of thread local singleton which can be replaced with a scoped construct?
//global scope singleton<my_object> my_singleton;
void foo() { my_singleton.instance().use_singleton(); // the globaly scoped one or a local replacement. }
void bar() { scoped_replacer _ (my_singleton); // replace my_object of baz with a copy my_singleton.instance().perform_local_modification(); foo(); // at this point my_object of baz is reinstantiated }
void baz() { scoped_replacer _ (my_singleton, my_object()); // replace the initial my_object
// with a copy of the second parameter foo(); // at this point the original my_object is reinstantiated }
int main() { baz(); }
In practice it is a form of dynamic scoping, which might be more useful and flexible than a static singleton. You definitely want this dynamic scoped object to be per thread.
I haven't read Boost.Singleton documentation, maybe it already allows such a functionality.
I'm not sure I understand the purpose of the code provided, but it seems to be sufficiently trivial to implement the facility you describe on top of what's provided. Regards, Tobias

On Jan 16, 2008 9:07 AM, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Giovanni Piero Deretta wrote:
On Jan 15, 2008 12:21 PM, Anthony Williams <anthony_w.geo@yahoo.com> wrote:
John Torjo <john.groups <at> torjo.com> writes:
Today starts the formal Fast-Track review of the Boost.Utility/Singleton library. This is a very useful utility, so I'm expecting lots of reviews ;) * What is your evaluation of the potential usefulness of the library? I don't think this is at all useful. People should not be encouraged to use singletons, as there is already a tendency towards overuse. In most circumstances, singletons are a poor design choice, so there is little requirement for their use.
I consider singletons just another form of globals and thus bad style.
Let's see:
"I consider if, else, for, do, while and the ternary operator just another form of goto and therefore bad style."
;-)
Except that 'if', 'else' and friends are a *restricted* form of goto (i.e. the 'structured' in structured programming) and are thus acceptable. In general, a singleton hardly adds any restriction to global (except from being thread safe). :)
[...] What about a form of thread local singleton which can be replaced with a scoped construct? [ code snipped ] In practice it is a form of dynamic scoping, which might be more useful and flexible than a static singleton. You definitely want this dynamic scoped object to be per thread.
I haven't read Boost.Singleton documentation, maybe it already allows such a functionality.
I'm not sure I understand the purpose of the code provided, but it seems to be sufficiently trivial to implement the facility you describe on top of what's provided.
It was just a form of dynamic scoping ( http://en.wikipedia.org/wiki/Dynamic_scope#Dynamic_scoping ). Probably the code didn't communicate the intent well enough. And yes, it is would be trivial to implement on top of any kind of singleton (actually you do not need much more than a thread specific pointer). My point was that I would feel less guilty using such a singleton (if you can call it singleton at all): if you eventually discover that you actually needed more than one instance, you have an escape hatch. -- gpd

Giovanni Piero Deretta wrote:
On Jan 16, 2008 9:07 AM, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Giovanni Piero Deretta wrote:
On Jan 15, 2008 12:21 PM, Anthony Williams <anthony_w.geo@yahoo.com> wrote:
John Torjo <john.groups <at> torjo.com> writes:
Today starts the formal Fast-Track review of the Boost.Utility/Singleton library. This is a very useful utility, so I'm expecting lots of reviews ;) * What is your evaluation of the potential usefulness of the library? I don't think this is at all useful. People should not be encouraged to use singletons, as there is already a tendency towards overuse. In most circumstances, singletons are a poor design choice, so there is little requirement for their use. I consider singletons just another form of globals and thus bad style. Let's see:
"I consider if, else, for, do, while and the ternary operator just another form of goto and therefore bad style."
;-)
Except that 'if', 'else' and friends are a *restricted* form of goto (i.e. the 'structured' in structured programming) and are thus acceptable.
Let's see: "Singletons are 'structured' globals (i.e. the 'structure' in 'data structure') and are thus acceptable." ;-) Some more fun: "I/O registers are global and thus bad style, so I built a computer without. Still trying to telepathically use that thing, though." ;-)
In general, a singleton hardly adds any restriction to global (except from being thread safe). :)
Thread-safety is just a bonbon here: So let's take another look at the key responsibilities of a Singleton is for: 1. Making the user implement a class 1.1. encourages a well-defined object interface, 1.2. embraces a design that can easily be changed to use non-globally scoped objects instead, and 1.3. prevents pollution of the global namespace. 2. Providing on-demand initialization 2.1. makes non-trivial construction work with any ABI's shared libs, and 2.2. automatically resolves dependencies between Singletons. 3. Ensuring a single instance of the Singleton class 3.1. allows to properly model unique facilities (hardware, registries, etc.) in an object oriented fashion, and 3.2. allows to encapsulate a well-defined access point in the first place. Note that the need for 2.1. makes 1. even more important as you're limited to trivially constructible types writing a shared library that is supposed to work portably. OK, that's about it. I might have forgotten something, but I'm in a bit of a hurry, right now. Sorry. Regards, Tobias

Disclaimer: I'm just discussing the singleton patern per se. I haven't read the documentation of Boost.Singleton nor I can comment on its design. I'm not voting for nor aganist the library. On Jan 16, 2008 12:05 PM, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Giovanni Piero Deretta wrote:
On Jan 16, 2008 9:07 AM, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Giovanni Piero Deretta wrote:
[...] I consider singletons just another form of globals and thus bad style.
Let's see:
"I consider if, else, for, do, while and the ternary operator just another form of goto and therefore bad style."
Except that 'if', 'else' and friends are a *restricted* form of goto (i.e. the 'structured' in structured programming) and are thus acceptable.
Let's see:
"Singletons are 'structured' globals (i.e. the 'structure' in 'data structure') and are thus acceptable."
Hum, the difference between "structured programming" and goto-based programming is well known and I didn't feel the need to define it. (but if you really want to: http://en.wikipedia.org/wiki/Structured_programming) What is not obvious (to me at least) is how singletons are more structured (in the sense of 'data structure') than a global object.
Some more fun:
"I/O registers are global and thus bad style, so I built a computer without. Still trying to telepathically use that thing, though."
How *hardware* I/O registers have anything to do with software engineering best practices?
In general, a singleton hardly adds any restriction to global (except from being thread safe). :)
Thread-safety is just a bonbon here: So let's take another look at the key responsibilities of a Singleton is for:
1. Making the user implement a class 1.1. encourages a well-defined object interface, 1.2. embraces a design that can easily be changed to use non-globally scoped objects instead, and 1.3. prevents pollution of the global namespace.
2. Providing on-demand initialization 2.1. makes non-trivial construction work with any ABI's shared libs, and 2.2. automatically resolves dependencies between Singletons.
3. Ensuring a single instance of the Singleton class 3.1. allows to properly model unique facilities (hardware, registries, etc.) in an object oriented fashion, and 3.2. allows to encapsulate a well-defined access point in the first place. [...]
The problem is that most of these points just make globals more usable, do not really address the problem with globals: an implicitly shared resource. In particular:
1.2. embraces a design that can easily be changed to use non-globally scoped objects instead, and
How? Or you design upfront not to rely on a non global scoped object, passing around a state pointer and not assuming global visibility of changes or you don't.
3.1. allows to properly model unique facilities (hardware, registries, etc.) in an object oriented fashion, and
I do not think you can usefully provide an OO interface to hardware registers, and anyways what is unique in one release of your hardware might not be in the next one. There might be higher level abstractions that are best modelled as singletons. The point is, are these common enough that they deserve a generic solution? -- gpd

Giovanni Piero Deretta wrote:
Disclaimer: I'm just discussing the singleton patern per se. I haven't read the documentation of Boost.Singleton nor I can comment on its design. I'm not voting for nor aganist the library.
Yep, I'm aware of it. That's why I have kept the discussion free of all the special features provided by the library.
On Jan 16, 2008 12:05 PM, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Giovanni Piero Deretta wrote:
On Jan 16, 2008 9:07 AM, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Giovanni Piero Deretta wrote:
[...] I consider singletons just another form of globals and thus bad style. Let's see:
"I consider if, else, for, do, while and the ternary operator just another form of goto and therefore bad style."
Except that 'if', 'else' and friends are a *restricted* form of goto (i.e. the 'structured' in structured programming) and are thus acceptable. Let's see:
"Singletons are 'structured' globals (i.e. the 'structure' in 'data structure') and are thus acceptable."
Hum, the difference between "structured programming" and goto-based programming is well known and I didn't feel the need to define it. (but if you really want to: http://en.wikipedia.org/wiki/Structured_programming)
So should the difference between structured and unstructured data... Thanks, I do know what "structured programming" is (and I'm even a fan of it, avoiding too many 'return' statements and so). I was just playing with words: Just like a Singleton boils down to a global somewhere - structured flow constrol statements boil down to 'goto's. There are many good reasons to avoid global variables and Singletons address quite a few of them.
What is not obvious (to me at least) is how singletons are more structured (in the sense of 'data structure') than a global object.
Global objects are often not an alternative because they don't work (we can't assume constructors to be run in a portable, dynamic library).
Some more fun:
"I/O registers are global and thus bad style, so I built a computer without. Still trying to telepathically use that thing, though."
How *hardware* I/O registers have anything to do with software engineering best practices?
I'm not talking about the register's hardware. I'm talking about their representation in *software* ;-). My point is: Systems have globals.
In general, a singleton hardly adds any restriction to global (except from being thread safe). :) Thread-safety is just a bonbon here: So let's take another look at the key responsibilities of a Singleton is for:
1. Making the user implement a class 1.1. encourages a well-defined object interface, 1.2. embraces a design that can easily be changed to use non-globally scoped objects instead, and 1.3. prevents pollution of the global namespace.
2. Providing on-demand initialization 2.1. makes non-trivial construction work with any ABI's shared libs, and 2.2. automatically resolves dependencies between Singletons.
3. Ensuring a single instance of the Singleton class 3.1. allows to properly model unique facilities (hardware, registries, etc.) in an object oriented fashion, and 3.2. allows to encapsulate a well-defined access point in the first place. [...]
The problem is that most of these points just make globals more usable, do not really address the problem with globals: an implicitly shared resource.
There are resources that *are* global and thus shared. There is nothing wrong with that! The question arises how to best model them.
In particular:
1.2. embraces a design that can easily be changed to use non-globally scoped objects instead, and
How? Or you design upfront not to rely on a non global scoped object, passing around a state pointer and not assuming global visibility of changes or you don't.
We have the choice to use parameters instead of obtaining the Singleton instance globally for a subsystem and thus to simplify reuse.
3.1. allows to properly model unique facilities (hardware, registries, etc.) in an object oriented fashion, and
I do not think you can usefully provide an OO interface to hardware registers, and anyways what is unique in one release of your hardware might not be in the next one.
I don't think this discussion is coupled to a particular abstraction level. Registers become devices and devices become connections. Then there are registry services (extended type info to provide some framework-specific form of reflection, for instance), loggers, etc.
There might be higher level abstractions that are best modelled as singletons. The point is, are these common enough that they deserve a generic solution?
Yes, I think so. Especially because there are many subtle pitfalls in this area. Regards, Tobias

Anthony, thanks for your review. Anthony Williams wrote:
I don't think this is at all useful. People should not be encouraged to use singletons, as there is already a tendency towards overuse. In most circumstances, singletons are a poor design choice, so there is little requirement for their use.
Any design that's picked carelessly is poor or just at best a fluke. Having a framework internally use some Singletons can greatly simplify its use. Exposing a singleton to a user provides more flexibility than exposing a static interface (and can also improve performance). A "tendency towards overuse" is not a good reason to reject a library, as it won't stop overuse and encourages more half-baked solutions that are written in a hurry. The only thing you can do against overuse is to add your experience to the documentation in order to educate users about applicability.
* What is your evaluation of the design? * What is your evaluation of the implementation?
The design mixes several independent issues --- ensuring there is only one instance of a class and avoiding initialization order problems with on-demand initialization for starters.
A simple wrapper class that allows for on-demand initialization, would be useful. Conflating that with "there shall be at most one instance" is not.
Again, allowing for a preferred destruction sequence of objects with such on-demand initialization might also be useful, but does not belong with the one-instance constraint.
What is the point in managing construction order without static context? What is the point of having more than one instance of a class that lives in static context -- and how would it be captured syntacticly?
thread_specific_singleton is overly complex for what should just amount to a simple use of thread_specific_ptr.
It uses 'thread_specific_ptr' and has additional responsibilities. Could you be more specific, please?
I've written code that used singletons (and regretted it later), and used code that other people have written containing singletons.
So you should like this library: The design chosen allows you to easily substitute Singletons with Smart Pointers. Regards, Tobias

Tobias Schwinger <tschwinger@isonews2.com> writes:
thanks for your review.
You're welcome.
Anthony Williams wrote:
I don't think this is at all useful. People should not be encouraged to use singletons, as there is already a tendency towards overuse. In most circumstances, singletons are a poor design choice, so there is little requirement for their use.
Any design that's picked carelessly is poor or just at best a fluke.
Can't argue with that!
Having a framework internally use some Singletons can greatly simplify its use.
Possibly, but I don't think they're needed even then. If they're an implementation detail of the framework, you don't need to make things a singleton in order to ensure there is only one instance --- just create one.
Exposing a singleton to a user provides more flexibility than exposing a static interface (and can also improve performance).
I don't see how. You can easily rewrite a static interface to use a singleton internally. Having a framework provide the user with a (reference-counted) pointer to an interface suitably hides all the details.
A "tendency towards overuse" is not a good reason to reject a library, as it won't stop overuse and encourages more half-baked solutions that are written in a hurry.
It is better to educate people in better ways of doing things (and provide tools to make those things easy) than enable them to easily do something that's generally a bad idea.
* What is your evaluation of the design? * What is your evaluation of the implementation?
The design mixes several independent issues --- ensuring there is only one instance of a class and avoiding initialization order problems with on-demand initialization for starters.
A simple wrapper class that allows for on-demand initialization, would be useful. Conflating that with "there shall be at most one instance" is not.
Again, allowing for a preferred destruction sequence of objects with such on-demand initialization might also be useful, but does not belong with the one-instance constraint.
What is the point in managing construction order without static context?
Sometimes there are uses for globals. In those cases, it is important to manage the construction and destruction order, independent of how many instances of any given class there may be.
What is the point of having more than one instance of a class that lives in static context -- and how would it be captured syntacticly?
I can imagine a use for having lots of instances of boost::mutex at global scope --- each mutex protects a different thing. You don't need to capture the syntactic idea "there may be more than one of this class" --- that is the base level assumption.
thread_specific_singleton is overly complex for what should just amount to a simple use of thread_specific_ptr.
It uses 'thread_specific_ptr' and has additional responsibilities.
Could you be more specific, please?
thread_specific_ptr on its own provides for one instance of an object per thread. I disagree that a class should impose that there is one and only one instance per thread (and no globals) --- this is a decision for the user of a class, not for the class itself. As I understand from the docs, the additional responsibility is the destruction order management. I agree this is a useful facility to provide, and think it is independent of the singleton nature of the classes, so should be separated into its own class.
I've written code that used singletons (and regretted it later), and used code that other people have written containing singletons.
So you should like this library: The design chosen allows you to easily substitute Singletons with Smart Pointers.
I disagree. If people know something is a singleton, then they don't bother keep the reference around, as they can get it again later. Changing code that does that to code that can use a passed in instance requires adding parameters and/or storing references. You can't just change uses of a singleton to use a smart pointer instead without thought to *how* it's being used. Anthony -- Anthony Williams Just Software Solutions Ltd - http://www.justsoftwaresolutions.co.uk Registered in England, Company Number 5478976. Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

Anthony Williams wrote:
Tobias Schwinger <tschwinger@isonews2.com> writes:
thanks for your review.
You're welcome.
Anthony Williams wrote:
I don't think this is at all useful. People should not be encouraged to use singletons, as there is already a tendency towards overuse. In most circumstances, singletons are a poor design choice, so there is little requirement for their use. Any design that's picked carelessly is poor or just at best a fluke.
Can't argue with that!
Having a framework internally use some Singletons can greatly simplify its use.
Possibly, but I don't think they're needed even then. If they're an implementation detail of the framework, you don't need to make things a singleton in order to ensure there is only one instance --- just create one.
What's so different between "using a Singleton" and "just creating one"? In fact, "just creating one" should be exactly what this library is all about ;-).
Exposing a singleton to a user provides more flexibility than exposing a static interface (and can also improve performance).
I don't see how. You can easily rewrite a static interface to use a singleton internally. Having a framework provide the user with a (reference-counted) pointer to an interface suitably hides all the details.
Yes, rewriting the code that uses the interface to use a non-static one seems less trivial of a task, however.
A "tendency towards overuse" is not a good reason to reject a library, as it won't stop overuse and encourages more half-baked solutions that are written in a hurry.
It is better to educate people in better ways of doing things (and provide tools to make those things easy) than enable them to easily do something that's generally a bad idea.
Without promoting Singletons people will use globals. And they will use more globals than they would use Singletons (especially in C++ because without we can't be sure initialization code is run if we're inside a dynamic library, so we probably end up using POD typed globals).
* What is your evaluation of the design? * What is your evaluation of the implementation? The design mixes several independent issues --- ensuring there is only one instance of a class and avoiding initialization order problems with on-demand initialization for starters.
A simple wrapper class that allows for on-demand initialization, would be useful. Conflating that with "there shall be at most one instance" is not.
Again, allowing for a preferred destruction sequence of objects with such on-demand initialization might also be useful, but does not belong with the one-instance constraint. What is the point in managing construction order without static context?
Sometimes there are uses for globals. In those cases, it is important to manage the construction and destruction order, independent of how many instances of any given class there may be.
OK. With a Singleton, the type serves as the key to access the global which I personally find quite elegant. A singleton can easily hold several instances of any other class, if a container is put into it. Further you can use multiple-inheritance to instantiate many singletons with a common subobject at compile time. So what are the alternatives (concrete interface proposals, please)?
What is the point of having more than one instance of a class that lives in static context -- and how would it be captured syntacticly?
I can imagine a use for having lots of instances of boost::mutex at global scope --- each mutex protects a different thing. You don't need to capture the syntactic idea "there may be more than one of this class" --- that is the base level assumption.
Interestingly, you show us that in this very case the things you try to protect should be 'mutexed_singleton'S to avoid namespace pollution and to add clarity ;-).
thread_specific_singleton is overly complex for what should just amount to a simple use of thread_specific_ptr. It uses 'thread_specific_ptr' and has additional responsibilities.
Could you be more specific, please?
thread_specific_ptr on its own provides for one instance of an object per thread. I disagree that a class should impose that there is one and only one instance per thread (and no globals) --- this is a decision for the user of a class, not for the class itself. As I understand from the docs, the additional responsibility is the destruction order management. I agree this is a useful facility to provide, and think it is independent of the singleton nature of the classes, so should be separated into its own class.
The responsibilities of a Singleton. Citing another post (sorry for the redundancy -- I think I'll add a brushed-up version of this list to the documentation).
I've written code that used singletons (and regretted it later), and used code that other people have written containing singletons. So you should like this library: The design chosen allows you to easily substitute Singletons with Smart Pointers.
I disagree. If people know something is a singleton, then they don't bother keep the reference around, as they can get it again later. Changing code that does that to code that can use a passed in instance requires adding parameters and/or storing references. You can't just change uses of a singleton to use a smart pointer instead without thought to *how* it's being used.

Tobias Schwinger <tschwinger <at> isonews2.com> writes:
Anthony Williams wrote:
Tobias Schwinger <tschwinger <at> isonews2.com> writes:
Anthony Williams wrote: Having a framework internally use some Singletons can greatly simplify its use.
Possibly, but I don't think they're needed even then. If they're an implementation detail of the framework, you don't need to make things a singleton in order to ensure there is only one instance --- just create one.
What's so different between "using a Singleton" and "just creating one"?
A singleton enforces that there is only one global instance with global accessibility. If you just create one (and pass it down by dependency injection) then the decision to just create one is made at the top level (where it belongs), and the client code doesn't have to be fussed with how many instances there are --- just that it can use the one provided. void some_function(Logger& logger) { logger.log("something"); } int main() { Logger myLogger; // ooh look, just one some_function(myLogger); } vs void some_function() { singleton<Logger>::instance()->log("something"); } int main() { some_function(); }
In fact, "just creating one" should be exactly what this library is all about .
Singleton is also called the Highlander pattern --- there can be only one.
Exposing a singleton to a user provides more flexibility than exposing a static interface (and can also improve performance).
I don't see how. You can easily rewrite a static interface to use a singleton internally. Having a framework provide the user with a (reference-counted) pointer to an interface suitably hides all the details.
Yes, rewriting the code that uses the interface to use a non-static one seems less trivial of a task, however.
shared_ptr<Logger> getLogger(); void some_function() { getLogger()->log("something"); } Client code doesn't have to know how many loggers there are. You could also pass in a context object or factory: void some_function(Context& context) { context.getLogger()->log("something"); }
A "tendency towards overuse" is not a good reason to reject a library, as it won't stop overuse and encourages more half-baked solutions that are written in a hurry.
It is better to educate people in better ways of doing things (and provide tools to make those things easy) than enable them to easily do something that's generally a bad idea.
Without promoting Singletons people will use globals. And they will use more globals than they would use Singletons (especially in C++ because without we can't be sure initialization code is run if we're inside a dynamic library, so we probably end up using POD typed globals).
Dependency injection is my preferred means, rather than globals or singletons. It has the side effect that you can decide on an initialization order that best suits your uses.
* What is your evaluation of the design? * What is your evaluation of the implementation? The design mixes several independent issues --- ensuring there is only one instance of a class and avoiding initialization order problems with on-demand initialization for starters.
A simple wrapper class that allows for on-demand initialization, would be useful. Conflating that with "there shall be at most one instance" is not.
Again, allowing for a preferred destruction sequence of objects with such on-demand initialization might also be useful, but does not belong with the one-instance constraint. What is the point in managing construction order without static context?
Sometimes there are uses for globals. In those cases, it is important to manage the construction and destruction order, independent of how many instances of any given class there may be.
OK. With a Singleton, the type serves as the key to access the global which I personally find quite elegant.
and which I find to be the biggest problem with singletons.
A singleton can easily hold several instances of any other class, if a container is put into it.
Further you can use multiple-inheritance to instantiate many singletons with a common subobject at compile time.
So what are the alternatives (concrete interface proposals, please)?
One of the benefits you cite for your singleton design is the construction-on-demand, which ensures that things are always constructed when required. In that case, how about providing a class: template<typename T> class construct_on_demand; so you can create instances like: construct_on_demand<Logger> myLogger; and any call to myLogger->log() will ensure that the object is constructed before first use. The appropriate operator-> call can also manage destruction order if required. Alternatively, if you just pass in a factory or context object, as in my example above, the getLogger() function can ensure the logger object is constructed before use.
What is the point of having more than one instance of a class that lives in static context -- and how would it be captured syntacticly?
I can imagine a use for having lots of instances of boost::mutex at global scope --- each mutex protects a different thing. You don't need to capture the syntactic idea "there may be more than one of this class" --- that is the base level assumption.
Interestingly, you show us that in this very case the things you try to protect should be 'mutexed_singleton'S to avoid namespace pollution and to add clarity .
That was the first thought off the top of my head. It may be that a Locked<T> template (such as that mentioned by Phil Endecott) would be a good idea, but even then you've got multiple instances of the Locked<> template at global scope. My point is that just because something is a global doesn't mean you only want one instance of that *class*. Anthony

Anthony Williams <anthony_w.geo <at> yahoo.com> writes:
Tobias Schwinger <tschwinger <at> isonews2.com> writes:
Anthony Williams wrote:
Tobias Schwinger <tschwinger <at> isonews2.com> writes:
Anthony Williams wrote: Having a framework internally use some Singletons can greatly simplify its use.
Possibly, but I don't think they're needed even then. If they're an implementation detail of the framework, you don't need to make things a singleton in order to ensure there is only one instance --- just create
one.
What's so different between "using a Singleton" and "just creating one"?
A singleton enforces that there is only one global instance with global accessibility. If you just create one (and pass it down by dependency injection) then the decision to just create one is made at the top level (where it belongs), and the client code doesn't have to be fussed with how many instances there are --- just that it can use the one provided.
void some_function(Logger& logger) { logger.log("something"); }
int main() { Logger myLogger; // ooh look, just one some_function(myLogger); }
This design has obvios drawback, right: you need to pass the instance around. Global free function is as bad as global variables IMO and as bad as singlton for what it worth. Singleton has one advantage - compiler support. If you working in uncertan environment it might help (and main unscertanty are people who are using your library), if having multiple instance is actually causing some inconsistency or allow any other kind of misuse. There are other patterns that can be used (Monostate for example), but singleton is as simple and easier to generalize. Gennadiy

On Jan 17, 2008 6:06 PM, Gennadiy Rozental <rogeeff@gmail.com> wrote:
Anthony Williams <anthony_w.geo <at> yahoo.com> writes:
A singleton enforces that there is only one global instance with global accessibility. If you just create one (and pass it down by dependency injection) then the decision to just create one is made at the top level (where it belongs), and the client code doesn't have to be fussed with how many instances there are --- just that it can use the one provided.
void some_function(Logger& logger) { logger.log("something"); }
int main() { Logger myLogger; // ooh look, just one some_function(myLogger); }
This design has obvios drawback, right: you need to pass the instance around.
Some consider this a feature.
Global free function is as bad as global variables IMO and as bad as singlton for what it worth.
How is a global free function is as bad as a global variable? You cannot mutate a function, while you can certainly mutate a variable. What is bad is not the visibility, but the mutability. (I do not think anybody has problems with global constants). I agree that a global variable is as bad as a singleton, though. -- gpd

Giovanni Piero Deretta <gpderetta <at> gmail.com> writes:
How is a global free function is as bad as a global variable? You cannot mutate a function, while you can certainly mutate a variable.
It's really depends on type returned by yout global free function. It you need to invoke mutating operation it's going to be T&. And you can mutate all you want. If you don't need to mutate, you can have T const as a type of global variable and you can't mutate it either. Gennadiy

Anthony Williams wrote:
Tobias Schwinger <tschwinger <at> isonews2.com> writes:
In fact, "just creating one" should be exactly what this library is all about .
Singleton is also called the Highlander pattern --- there can be only one.
Cool! I think I'll rename the library when it gets accepted :-P.
OK. With a Singleton, the type serves as the key to access the global which I personally find quite elegant.
and which I find to be the biggest problem with singletons.
I see. And it seems to me that you overrate the problem part of it.
A singleton can easily hold several instances of any other class, if a container is put into it.
Further you can use multiple-inheritance to instantiate many singletons with a common subobject at compile time.
So what are the alternatives (concrete interface proposals, please)?
One of the benefits you cite for your singleton design is the construction-on-demand, which ensures that things are always constructed when required. In that case, how about providing a class:
template<typename T> class construct_on_demand;
so you can create instances like:
construct_on_demand<Logger> myLogger;
and any call to myLogger->log() will ensure that the object is constructed before first use.
The appropriate operator-> call can also manage destruction order if required.
Interesting. Now let's see how we'd do it with Singletons: class Logger; struct myLogger : Logger, boost::singleton<myLogger> {}; // Please note that: // o We do not waste BSS space, and // o the instance can be allocated statically. OK, we use a type instead of the variable name. So what?!
What is the point of having more than one instance of a class that lives in static context -- and how would it be captured syntacticly? I can imagine a use for having lots of instances of boost::mutex at global scope --- each mutex protects a different thing. You don't need to capture the syntactic idea "there may be more than one of this class" --- that is the base level assumption.
Interestingly, you show us that in this very case the things you try to protect should be 'mutexed_singleton'S to avoid namespace pollution and to add clarity .
That was the first thought off the top of my head. It may be that a Locked<T> template (such as that mentioned by Phil Endecott) would be a good idea, but even then you've got multiple instances of the Locked<> template at global scope. My point is that just because something is a global doesn't mean you only want one instance of that *class*.
Yes, I do understand your point. I don't believe it is that important, however :-). Regards, Tobias

Whoops, I accidentally hit 'submit'... Here's the second part: Anthony Williams wrote:
thread_specific_singleton is overly complex for what should just amount to a simple use of thread_specific_ptr. It uses 'thread_specific_ptr' and has additional responsibilities.
Could you be more specific, please?
thread_specific_ptr on its own provides for one instance of an object per thread. I disagree that a class should impose that there is one and only one instance per thread (and no globals) --- this is a decision for the user of a class, not for the class itself. As I understand from the docs, the additional responsibility is the destruction order management. I agree this is a useful facility to provide, and think it is independent of the singleton nature of the classes, so should be separated into its own class.
The responsibilities of a Singleton. Citing another post (sorry for the redundancy -- I think I'll add a brushed-up version of this list to the documentation): 1. Making the user implement a class 1.1. encourages a well-defined object interface, 1.2. embraces a design that can easily be changed to use non-globally scoped objects instead, and 1.3. prevents pollution of the global namespace. 2. Providing on-demand initialization 2.1. makes non-trivial construction work with any ABI's shared libs, and 2.2. automatically resolves dependencies between Singletons. 3. Ensuring a single instance of the Singleton class 3.1. allows to properly model unique facilities (hardware, registries, etc.) in an object oriented fashion, and 3.2. allows to encapsulate a well-defined access point in the first place.
I've written code that used singletons (and regretted it later), and used code that other people have written containing singletons. So you should like this library: The design chosen allows you to easily substitute Singletons with Smart Pointers.
I disagree. If people know something is a singleton, then they don't bother keep the reference around, as they can get it again later. Changing code that does that to code that can use a passed in instance requires adding parameters and/or storing references. You can't just change uses of a singleton to use a smart pointer instead without thought to *how* it's being used.
I won't argue on this one. I can imagine that having to refactor a mess like this is a most unpleasant experience. Still it's not the fault of the Singletons but of developer's laziness: At least the developers in the project you mention had a choice whether to write flexible code or not. With globals and static functions, they wouldn't have had a choice but to make a mess. Regards, Tobias

Tobias Schwinger <tschwinger <at> isonews2.com> writes:
Anthony Williams wrote:
The responsibilities of a Singleton. Citing another post (sorry for the redundancy -- I think I'll add a brushed-up version of this list to the documentation):
1. Making the user implement a class 1.1. encourages a well-defined object interface,
Only if people can manage to use one singleton per role.
1.2. embraces a design that can easily be changed to use non-globally scoped objects instead, and
I disagree there. Uses of singletons cannot easily be changed to use non-globally scoped objects.
1.3. prevents pollution of the global namespace.
Not really: you have to provide a class name rather than a variable name.
2. Providing on-demand initialization 2.1. makes non-trivial construction work with any ABI's shared libs, and 2.2. automatically resolves dependencies between Singletons.
As I mentioned before, this is orthogonal to Singleton: the responsibility of singleton is to ensure there is one and only one instance, not to provide on-demand initialization. This is also easily provided by other means.
3. Ensuring a single instance of the Singleton class 3.1. allows to properly model unique facilities (hardware, registries, etc.) in an object oriented fashion, and
This is the crux of the matter. Just because there is only one printer, doesn't mean that you have to enforce a single instance of the Printer class. Just create one instance, and pass it down with dependency injection.
3.2. allows to encapsulate a well-defined access point in the first place.
It might be well-defined, but I'd argue that it's not well-designed.
I've written code that used singletons (and regretted it later), and used code that other people have written containing singletons. So you should like this library: The design chosen allows you to easily substitute Singletons with Smart Pointers.
I disagree. If people know something is a singleton, then they don't bother keep the reference around, as they can get it again later. Changing code that does that to code that can use a passed in instance requires adding parameters and/or storing references. You can't just change uses of a singleton to use a smart pointer instead without thought to *how* it's being used.
I won't argue on this one. I can imagine that having to refactor a mess like this is a most unpleasant experience.
Still it's not the fault of the Singletons but of developer's laziness: At least the developers in the project you mention had a choice whether to write flexible code or not. With globals and static functions, they wouldn't have had a choice but to make a mess.
Singletons *are* globals. Anthony

Anthony Williams wrote:
Tobias Schwinger <tschwinger <at> isonews2.com> writes:
I've written code that used singletons (and regretted it later), and used code that other people have written containing singletons. So you should like this library: The design chosen allows you to easily substitute Singletons with Smart Pointers. I disagree. If people know something is a singleton, then they don't bother keep the reference around, as they can get it again later. Changing code that does that to code that can use a passed in instance requires adding parameters and/or storing references. You can't just change uses of a singleton to use a smart pointer instead without thought to *how* it's being used. I won't argue on this one. I can imagine that having to refactor a mess
Anthony Williams wrote: like this is a most unpleasant experience.
Still it's not the fault of the Singletons but of developer's laziness: At least the developers in the project you mention had a choice whether to write flexible code or not. With globals and static functions, they wouldn't have had a choice but to make a mess.
Singletons *are* globals.
OK, that was a bit unclear. Let's put it this way: It's not globals that are evil but accessing them all over the place (or "coupling" to use the technical term that describes the problem). Regards, Tobias

Tobias Schwinger:
Singletons *are* globals.
OK, that was a bit unclear. Let's put it this way:
It's not globals that are evil but accessing them all over the place (or "coupling" to use the technical term that describes the problem).
Coupling is why people use singletons. Were there no coupling, there would be no need to constrain the number of instances. The whole point of having a single instance it to allow modules to couple themselves to it, and be sure that they can communicate with other coupled modules via its state. Note that I'm using singleton here to mean singleton and not to mean "a solution to the initialization order problem" (which is independent of the number of instances a type allows).

Peter Dimov wrote:
Tobias Schwinger:
Singletons *are* globals. OK, that was a bit unclear. Let's put it this way:
It's not globals that are evil but accessing them all over the place (or "coupling" to use the technical term that describes the problem).
Coupling is why people use singletons. Were there no coupling, there would be no need to constrain the number of instances. The whole point of having a single instance it to allow modules to couple themselves to it, and be sure that they can communicate with other coupled modules via its state.
Thanks for throwing in the wise words, Peter. With this terminology the moral of Anthony's experience report boils down to: "Don't write too much code against an interface that will eventually change". :-) Regards, Tobias

Tobias Schwinger <tschwinger <at> isonews2.com> writes:
Peter Dimov wrote:
Tobias Schwinger:
Singletons *are* globals. OK, that was a bit unclear. Let's put it this way:
It's not globals that are evil but accessing them all over the place (or "coupling" to use the technical term that describes the problem).
Coupling is why people use singletons. Were there no coupling, there would be no need to constrain the number of instances. The whole point of having a single instance it to allow modules to couple themselves to it, and be sure that they can communicate with other coupled modules via its state.
Thanks for throwing in the wise words, Peter.
Yes. People use singletons to ensure that code is coupled to the decision that there can be only one instance of a particular class. As you say yourself, excess coupling is bad. In particular, most code that is coupled using singletons has no need to know about the "one instance" constraint --- it just needs *some* instance to use. Sometimes it needs to know that it's the same instance as one being used elsewhere, but there are other solutions to this than singletons (e.g. explicitly passing the reference around), which avoid the coupling to the "there can be only one" design decision.
With this terminology the moral of Anthony's experience report boils down to:
"Don't write too much code against an interface that will eventually change".
That's certainly sensible advice. In my experience, singletons introduce excessive coupling, and make the code that uses the singleton hard to test. I am strongly opposed to the use of singletons in almost all circumstances, and strongly opposed to the idea of any library designed to make implementing singletons easier. Anthony

My vote: Accept the current implementation. I initially thought boost should reject this singleton implementation because it bundles too many concepts into one package. Others have pointed out some clear factorization points. They looked something like: template <class T> class singleton; template <class T> class mutexed_ptr; template <class T> class mutexed_singleton : public singleton<mutexed_ptr<T> >; But a bird in hand is worth two in the bush... While good ideas have been put forth, I don't see their implementation coming soon; and most of these changes should have little effect on the API. Ramblings: Despite the naysayers, boost needs a singleton framework (or at least some concise documentation on how to implement them portably). Ignoring a common idiom won't make it go away. A few purposes for singletons: 1) only create a single object As Anthony points out, this is generally bad and shortsighted. 2) establish a central point of communication This can be a good thing. 3) work around foreign APIs Singletons can save the day when working with callbacks in foreign APIs. Until everyone starts using functor objects or the like, singletons may be the only way to pass "extra parameters" through another library's callback API. 4) simplify public APIs Mirroring the previous point, "dependency injection" can horribly clutter an API. Its fine for a couple things; but carried too far, it can introduce tigher coupling between and an application and a library since the application now has an active role in passing the library state around. This is especially important when adding a new library to "legacy code" where social factors may prevent dependency injection while singletons allow more isolated changes. Of these use cases, only 1 and 2 require special static initialization (3 and 4 may use an explicit init() call). Similarly, none of them require locking semantics, though locking should be easy to specify/enable. - Daniel

On Monday 14 January 2008 12:10 pm, John Torjo wrote:
|- boost::mutexed_singleton| : additionally ensures that concurrent access to the instance is mutually exclusive. In other words, only one thread can access the instance at a given time.
This seems like a combination of two independent ideas: a singleton and a monitor. I'd rather see independent monitor object support in boost, then the user could combine them as desired (or not, as monitors certainly don't have to be singletons). I've recently implemented two boost-licensed monitor classes, one pointer-like, and one value-like. See: http://www.comedi.org/projects/libpoet/boostbook/doc/boostbook/html/poet/mon... This isn't a real review, I just wanted to comment on the mutexed_singleton concept. I'm really more interested in the monitor aspect than the singleton (I always have to remind myself what the rationale is for using a singleton when I find myself writing one). -- Frank

Frank Mori Hess wrote:
On Monday 14 January 2008 12:10 pm, John Torjo wrote:
|- boost::mutexed_singleton| : additionally ensures that concurrent access to the instance is mutually exclusive. In other words, only one thread can access the instance at a given time.
This seems like a combination of two independent ideas: a singleton and a monitor.
Anything global begs for synchronization in multi-threaded context. So, yes for the "monitor" part (using the scientific definition not the one used by the Java programming language) and no for the "independent" part of your sentence. The dependency between the two is an unidirectional one, though. As synchronization makes sense without a Singleton but not vice versa (that is given a multi-threaded environment).
http://www.comedi.org/projects/libpoet/boostbook/doc/boostbook/html/poet/mon...
Nice! Regards, Tobias

Today starts the formal Fast-Track review of the Boost.Utility/Singleton library.
I've never made much use of singletons, but I won't let that stop me from commenting... My thoughts: 1. There's no "un-synchronised" version, for use in single-threaded programs or when all (first) accesses come from the same thread. 2. The "mutexed access" feature can be useful in situation other than singletons; can't something more general-purpose be provided? I use a template class Lockable<T> which grants reader/writer-exclusive access to a contained T. (Reader/writer locking could be useful here.) (It might be useful to make the mutex type a template parameter, with a sensible default; I have a few mutexes of my own, with a boost::mutex-compatible interface.) 3. Function static variables can be thought of as "local singletons", but they aren't synchronised. It would be great if we could replace "static T t(.....);" with "safe_static<T> t(.....);" and get the same semantics. 4. As far as I can see, most of what this library does is to simplify this: class my_thing: noncopyable { my_thing() { ...... } public: my_thing& instance() { static my_thing i; return i; } }; to this: class my_thing: public singleton<my_thing> { public: my_thing(restricted) { ....... } }; which is a saving, but not a huge one, and the fact that there's "behind-the-scenes magic you have to understand and trust" going on in the second case, compared to only "C++ 101" language features in the first one, makes me prefer not to use it. EXCEPT, of course, for the thread-safety feature. Which brings me back to my points above. If instead we could write: class my_thing: noncopyable { my_thing() { ...... } public: my_thing& instance() { safe_static<my_thing> i; // or maybe SAFE_STATIC(my_thing,i) if we have to return i; } }; then I think I would be happy.
* What is your evaluation of the design?
See above.
* What is your evaluation of the implementation?
Not studied.
* What is your evaluation of the documentation?
Good.
* What is your evaluation of the potential usefulness of the library?
I suppose I might use it if I ever needed a thread-safe singleton.
* Did you try to use the library? With what compiler?
No.
* How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
30 mins reading the docs and writing this message.
* Are you knowledgeable about the problem domain?
Not especially. I know a bit about threads.
And finally, every review should answer this question:
* Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion.
My answer is yes, but.... Would other people like to comment about the quantity of stuff in Boost, and the extent to which sheer volume will slow down future releases? I worry that by accepting libraries simply because they are "good enough", we'll end up unable ever to release anything! If instead we were to focus on really compelling core stuff that ought to end up in the standard library, could we accelerate the release process? Cheers, Phil.

On Tuesday 15 January 2008 20:03, Phil Endecott wrote:
1. There's no "un-synchronised" version, for use in single-threaded programs or when all (first) accesses come from the same thread.
I took the bit in the documentation saying "implementing identical behavior in a single-threaded environment" to mean they are all un-synchronised, if you compile for example using gcc without the -pthread option.
2. The "mutexed access" feature can be useful in situation other than singletons; can't something more general-purpose be provided? I use a template class Lockable<T> which grants reader/writer-exclusive access to a contained T. (Reader/writer locking could be useful here.) (It might be useful to make the mutex type a template parameter, with a sensible default; I have a few mutexes of my own, with a boost::mutex-compatible interface.)
Is any of this available publically, or documentation for it available publically? -- Frank

Frank Mori Hess wrote:
On Tuesday 15 January 2008 20:03, Phil Endecott wrote:
1. There's no "un-synchronised" version, for use in single-threaded programs or when all (first) accesses come from the same thread.
I took the bit in the documentation saying "implementing identical behavior in a single-threaded environment" to mean they are all un-synchronised, if you compile for example using gcc without the -pthread option.
Right, but in a large application I may have all uses of class X from a single thread, but still with other threads in completely different parts of the program (so I have to compile with -pthread).
2. The "mutexed access" feature can be useful in situation other than singletons; can't something more general-purpose be provided? I use a template class Lockable<T> which grants reader/writer-exclusive access to a contained T. (Reader/writer locking could be useful here.) (It might be useful to make the mutex type a template parameter, with a sensible default; I have a few mutexes of my own, with a boost::mutex-compatible interface.)
Is any of this available publically, or documentation for it available publically?
At http://svn.chezphil.org/libpbe/trunk/include/Locked.hh (note Locked<T>, not Lockable<T> as I mis-wrote above): // This provides a class template that augments a variable with a mutex, and // allows access only when the mutex is locked. Example: // // typedef Locked< vector<int> > x_t; // x_t x; // // // We can only modify x via an x_t::writer: // x_t::writer xw; // // Creating xw locks the mutex. // // xw behaves like a pointer to the underlying vector<int>: // xw->push_back(123); // xw->push_back(321); // // The lock is released when xw goes out of scope. // // To read, use an x_t::reader. It behaves like a const pointer to the // underlying data. // // The mutex and lock types can be specified with template parameters, but // they default to the boost versions. // // I had hoped to allow conversion-to-reference for the writer and reader, so // that you could write xw.push_back(123) rather than xw->push_back(123). // But this didn't work, presumably because I don't really understand how // implict type conversion is supposed to work. My attempt is still present, // commented out. It looks as if it hasn't done real reader/writer locking since that feature was removed from Boost. As for the mutexes, I suggest that you search for my name in this list's archive. This is GPL licensed. Let me know if you'd prefer something else. Regards, Phil.

Phil, thanks for your positive review. I almost overlooked it. Phil Endecott wrote:
Today starts the formal Fast-Track review of the Boost.Utility/Singleton library.
I've never made much use of singletons, but I won't let that stop me from commenting...
My thoughts:
1. There's no "un-synchronised" version, for use in single-threaded programs or when all (first) accesses come from the same thread.
If there is just a single thread all Singletons behave the same. If you want to avoid the initialization check within one thread you can 'lease' a non-mutexed Singleton. Yes, the creation will be synchronized but it's very unlikely that this part will become a performance bottleneck.
2. The "mutexed access" feature can be useful in situation other than singletons; can't something more general-purpose be provided? I use a template class Lockable<T> which grants reader/writer-exclusive access to a contained T. (Reader/writer locking could be useful here.) (It might be useful to make the mutex type a template parameter, with a sensible default; I have a few mutexes of my own, with a boost::mutex-compatible interface.)
You can still use 'singleton<T>' and implement a custom synchronization scheme. I think that's best if you want to use r/w locks effectively. Further, a mutex can be more efficient than r/w locks; AFAIK those only pay off if there's enough concurrency going on (I might be wrong).
3. Function static variables can be thought of as "local singletons", but they aren't synchronised. It would be great if we could replace "static T t(.....);" with "safe_static<T> t(.....);" and get the same semantics.
Is it implementable? Regards, Tobias

If instead we were to focus on really compelling core stuff that ought to end up in the standard library, could we accelerate the release process?
What do you mean by core? Everyone has its own idea of what "core" means ;) Best, John
Cheers, Phil.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- http://John.Torjo.com -- C++ expert ... call me only if you want things done right

"John Torjo" <john.groups@torjo.com> wrote in message news:478B978A.6090503@torjo.com...
Hi all,
* What is your evaluation of the design?
In short: in places too complicated, in places plain wrong. In details: 1. mutexed_singleton This should be singleton<synchronized<T> >. Current design mixes two orthogonal concepts: uniqueness of class instance and class methods synchronization and this is obviously wrong. 2. thread_specific_singleton. The same as above. This should be singleton<thread_specific<T> >. Current design mixes two orthogonal concepts: uniqueness of class instance and thread specific object storage. 3. public construction and boost::restricted I don't like this solution and very much prefer private constructor with friend declaration (especially if encapsulated into single macro). This will be a never ending source of confusion (what is boost::restricted, can I have restricted access, how do I create restricted instances etc) and doesn't really protect - once can still create instances of my class with valid C++ code. 4. DLL support Explanation of DLL issues in docs is very unclear. No examples provided. No tests showing that solution actually works. Accordingly I can't really comment on it, but from what I got I really doubt it. 5. instance proxy. Given complete absence of rationale of this design, I can't really devise why is was chosen, but it seems wrong. We end up with pricy complication with unclear purposes. What's wrong with just returning T& from instance method? The same time we can get rid of all this member_dereference staff and it's limitations. 6. lease. Pretty much the same as above. synchronized<T> should have it's own lock facility. Otherwise instance() should be straightforward access to the instance and no need for any proxies/leases. 7. MT support Setting aside mutexed and thread specific singletons covered above, regular singleton handling of MT is wrong as well. In simple words my primary complain: you can't use define based solution for switching MT/non MT. It should be template parameter. As of now there is no singleton that can work in presence of threads but without disregard to them. 8. No Meyer's singleton What if do not want all this manager staff?
* What is your evaluation of the implementation? * What is your evaluation of the documentation?
As usual these days, scarce to the point of being useless. It also incorrect - it doesn't cover third template parameter in reference for example. Singleton is very basic and quite well known design pattern The documentation should explain in details all design choices, compare with different solutions and explain advantages. There are number of existing pitfalls with singleton pattern - all have to be covered, starting with double locking idiom problem and they it's solved (if they are).
* What is your evaluation of the potential usefulness of the library?
Shaky. We'll either keep using trivial Meyer's-like singleton or need solution which actually make sense and solve real problems. In later case it still need require big disclaimer somewhere on top: do not overuse.
* Did you try to use the library? With what compiler?
No.
Did you have any problems? * How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
study
* Are you knowledgeable about the problem domain?
Yes.
And finally, every review should answer this question:
* Do you think the library should be accepted as a Boost library?
No. Gennadiy

Gennadiy, thanks for your through and through negative review. Gennadiy Rozental wrote:
"John Torjo" <john.groups@torjo.com> wrote in message news:478B978A.6090503@torjo.com...
Hi all,
* What is your evaluation of the design?
In short: in places too complicated, in places plain wrong.
In details:
1. mutexed_singleton
This should be singleton<synchronized<T> >. Current design mixes two orthogonal concepts: uniqueness of class instance and class methods synchronization and this is obviously wrong.
2. thread_specific_singleton.
The same as above. This should be singleton<thread_specific<T> >. Current design mixes two orthogonal concepts: uniqueness of class instance and thread specific object storage.
One could implement what you propose. It would probably even make things easier on my side. It complicates client code and compromises the replaceability of all the Singleton templates, which is a mistake.
3. public construction and boost::restricted
I don't like this solution and very much prefer private constructor with friend declaration (especially if encapsulated into single macro). This will be a never ending source of confusion (what is boost::restricted, can I have restricted access, how do I create restricted instances etc) and doesn't really protect - once can still create instances of my class with valid C++ code.
You're still free to use a private constructor and a friend declaration.
4. DLL support
Explanation of DLL issues in docs is very unclear. No examples provided. No tests showing that solution actually works. Accordingly I can't really comment on it, but from what I got I really doubt it.
The test just hasn't been automated yet. And, yes, the documentation can use some improvement.
5. instance proxy.
Given complete absence of rationale of this design, I can't really devise why is was chosen, but it seems wrong. We end up with pricy complication with unclear purposes. What's wrong with just returning T& from instance method? The same time we can get rid of all this member_dereference staff and it's limitations.
What limitations are you talking about? The ability to have automatic locking when using a member pointer?
6. lease.
Pretty much the same as above. synchronized<T> should have it's own lock facility. Otherwise instance() should be straightforward access to the instance and no need for any proxies/leases.
Again, fails to see the advantage of a uniform interface.
7. MT support
Setting aside mutexed and thread specific singletons covered above, regular singleton handling of MT is wrong as well. In simple words my primary complain: you can't use define based solution for switching MT/non MT. It should be template parameter. As of now there is no singleton that can work in presence of threads but without disregard to them.
I can't get your point. There probably is none.
8. No Meyer's singleton
What if do not want all this manager staff?
What's "all this manager staff" and what's a "Meyers' singleton"? Regards, Tobias

Tobias Schwinger <tschwinger <at> isonews2.com> writes:
2. thread_specific_singleton.
The same as above. This should be singleton<thread_specific<T> >. Current design mixes two orthogonal concepts: uniqueness of class instance and thread specific object storage.
One could implement what you propose. It would probably even make things easier on my side.
It complicates client code
How come? If anything it simplify things. Let's say I want now more than one instance of the class, but still need syncronized access to it's methods. In your case I'll havereimplement the whole thing.
and compromises the replaceability of all the Singleton templates, which is a mistake.
I am not sure what exactly it compromises.
3. public construction and boost::restricted
I don't like this solution and very much prefer private constructor with friend declaration (especially if encapsulated into single macro). This will be a never ending source of confusion (what is boost::restricted, can I have restricted access, how do I create restricted instances etc) and doesn't really protect - once can still create instances of my class with valid C++ code.
You're still free to use a private constructor and a friend declaration.
Yes. But argue that you are trying to promote bad practice.
4. DLL support
Explanation of DLL issues in docs is very unclear. No examples provided. No tests showing that solution actually works. Accordingly I can't really comment on it, but from what I got I really doubt it.
The test just hasn't been automated yet. And, yes, the documentation can use some improvement.
As far as I can tell, simply there is no tests for this scenario.
5. instance proxy.
Given complete absence of rationale of this design, I can't really devise why is was chosen, but it seems wrong. We end up with pricy complication with unclear purposes. What's wrong with just returning T& from instance method? The same time we can get rid of all this member_dereference staff and it's limitations.
What limitations are you talking about?
in member_derefernce there is max_args macro
The ability to have automatic locking when using a member pointer?
Ability is good. Your design actually more on enforcement side.
6. lease.
Pretty much the same as above. synchronized<T> should have it's own lock facility. Otherwise instance() should be straightforward access to the instance and no need for any proxies/leases.
Again, fails to see the advantage of a uniform interface.
The simpler, the better. So this is actually other way around: what is an advantage of this lease API
7. MT support
Setting aside mutexed and thread specific singletons covered above, regular singleton handling of MT is wrong as well. In simple words my primary complain: you can't use define based solution for switching MT/non MT. It should be template parameter. As of now there is no singleton that can work in presence of threads but without disregard to them.
I can't get your point. There probably is none.
I meant "without regard to them". IOW BOOST_HAS_THREADS is global compile time switch which should have no bearings in design on singleton. regardless of this flag I may or may not want instance construction to be syncronized.
8. No Meyer's singleton
What if do not want all this manager staff?
What's "all this manager staff" and
I just want singleton. Don't care about it's distruction order. And don't need anyone to manage it.
what's a "Meyers' singleton"?
http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton... Pattern-Part-I/4/ Gennadiy

Gennadiy Rozental wrote:
Tobias Schwinger <tschwinger <at> isonews2.com> writes:
2. thread_specific_singleton.
The same as above. This should be singleton<thread_specific<T> >. Current design mixes two orthogonal concepts: uniqueness of class instance and thread specific object storage. One could implement what you propose. It would probably even make things easier on my side.
It complicates client code
How come? If anything it simplify things. Let's say I want now more than one instance of the class, but still need syncronized access to it's methods. In your case I'll havereimplement the whole thing.
and compromises the replaceability of all the Singleton templates, which is a mistake.
I am not sure what exactly it compromises.
'singleton<T>' and 'mutexed_singleton<T>' sharing the same syntax.
3. public construction and boost::restricted
I don't like this solution and very much prefer private constructor with friend declaration (especially if encapsulated into single macro). This will be a never ending source of confusion (what is boost::restricted, can I have restricted access, how do I create restricted instances etc) and doesn't really protect - once can still create instances of my class with valid C++ code. You're still free to use a private constructor and a friend declaration.
Yes. But argue that you are trying to promote bad practice.
Arguably. It works well to ensure the component is used as intended, it's brief and it optimizes out entirely.
4. DLL support
Explanation of DLL issues in docs is very unclear. No examples provided. No tests showing that solution actually works. Accordingly I can't really comment on it, but from what I got I really doubt it. The test just hasn't been automated yet. And, yes, the documentation can use some improvement.
As far as I can tell, simply there is no tests for this scenario.
I probably didn't include it in the archive.
5. instance proxy.
Given complete absence of rationale of this design, I can't really devise why is was chosen, but it seems wrong. We end up with pricy complication with unclear purposes. What's wrong with just returning T& from instance method? The same time we can get rid of all this member_dereference staff and it's limitations. What limitations are you talking about?
in member_derefernce there is max_args macro
Oh well...
The ability to have automatic locking when using a member pointer?
Ability is good. Your design actually more on enforcement side.
It's more about having just one interfaces for all Singleton variants.
6. lease.
Pretty much the same as above. synchronized<T> should have it's own lock facility. Otherwise instance() should be straightforward access to the instance and no need for any proxies/leases. Again, fails to see the advantage of a uniform interface.
The simpler, the better. So this is actually other way around: what is an advantage of this lease API
You can skip the initialization check.
7. MT support
Setting aside mutexed and thread specific singletons covered above, regular singleton handling of MT is wrong as well. In simple words my primary complain: you can't use define based solution for switching MT/non MT. It should be template parameter. As of now there is no singleton that can work in presence of threads but without disregard to them. I can't get your point. There probably is none.
I meant "without regard to them". IOW BOOST_HAS_THREADS is global compile time switch which should have no bearings in design on singleton. regardless of this flag I may or may not want instance construction to be syncronized.
The design doesn't change based on that macro. If there is just a single thread all Singletons behave the same -- with or without that macro defined. If you want to avoid the initialization check within one thread you can 'lease' a non-mutexed Singleton. Yes, the creation will be synchronized but it's very unlikely that this part will become a performance bottleneck.
8. No Meyer's singleton
What if do not want all this manager staff? What's "all this manager staff" and
I just want singleton. Don't care about it's distruction order. And don't need anyone to manage it.
OK, then just don't care and things just work. If you insist on Meyers' Singleton: Write it -- it's just a few lines :-).
what's a "Meyers' singleton"?
http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton... Pattern-Part-I/4/
OK, that's basically a Go4 Singleton implemented in C++. It might now work reliably in dynamic libraries with some ABIs. Regards, Tobias

Tobias Schwinger <tschwinger <at> isonews2.com> writes:
and compromises the replaceability of all the Singleton templates, which is a mistake.
I am not sure what exactly it compromises.
'singleton<T>' and 'mutexed_singleton<T>' sharing the same syntax.
In my suggestion there is single syntax, so nothing to share.
3. public construction and boost::restricted
I don't like this solution and very much prefer private constructor with friend declaration (especially if encapsulated into single macro). This will be a never ending source of confusion (what is boost::restricted, can I have restricted access, how do I create restricted instances etc) and doesn't really protect - once can still create instances of my class with valid C++ code. You're still free to use a private constructor and a friend declaration.
Yes. But argue that you are trying to promote bad practice.
Arguably. It works well to ensure the component is used as intended, it's brief and it optimizes out entirely.
No. It doesn't ensure that. One can still create instances of my class with valid C++. It's not brief implementation wise in comparison with doing nothing and an alternative is as brief usage wise.
4. DLL support
Explanation of DLL issues in docs is very unclear. No examples provided. No tests showing that solution actually works. Accordingly I can't really comment on it, but from what I got I really doubt it. The test just hasn't been automated yet. And, yes, the documentation can use some improvement.
As far as I can tell, simply there is no tests for this scenario.
I probably didn't include it in the archive.
So you can't state it works for DLL. No one is able to verify. Or do you expect us to believe your word?
5. instance proxy.
Given complete absence of rationale of this design, I can't really devise why is was chosen, but it seems wrong. We end up with pricy complication with unclear purposes. What's wrong with just returning T& from instance method? The same time we can get rid of all this member_dereference staff and it's limitations. What limitations are you talking about?
in member_derefernce there is max_args macro
Oh well...
The ability to have automatic locking when using a member pointer?
Ability is good. Your design actually more on enforcement side.
It's more about having just one interfaces for all Singleton variants.
I don't suggest having different interfaces for singletons. I argue that plain instance interface is all we need for all flavours of singleto, while what you present is at least 2: interface-> and lease.
6. lease.
Pretty much the same as above. synchronized<T> should have it's own lock facility. Otherwise instance() should be straightforward access to the instance and no need for any proxies/leases. Again, fails to see the advantage of a uniform interface.
The simpler, the better. So this is actually other way around: what is an advantage of this lease API
You can skip the initialization check.
local reference and Meyers' singleton are as good in this regard.
7. MT support
Setting aside mutexed and thread specific singletons covered above, regular singleton handling of MT is wrong as well. In simple words my primary complain: you can't use define based solution for switching MT/non MT.
It
should be template parameter. As of now there is no singleton that can work in presence of threads but without disregard to them. I can't get your point. There probably is none.
I meant "without regard to them". IOW BOOST_HAS_THREADS is global compile time switch which should have no bearings in design on singleton. regardless of this flag I may or may not want instance construction to be syncronized.
The design doesn't change based on that macro.
It does. You either do or don't do syncronization based on it.
If there is just a single thread all Singletons behave the same -- with or without that macro defined.
If you want to avoid the initialization check within one thread you can 'lease' a non-mutexed Singleton.
Yes, the creation will be synchronized but it's very unlikely that this part will become a performance bottleneck.
It's not about performance at all. The fact that BOOST_HAS_THREADS is defined, doesn't mean I plan to build MT application. In fact I may not link with pthread at all. For example it defined if _REENTRANT is defined. In general it defined if compiler *thinks* it's in multithreaded mode. On the other hand I can imagine a curcomstances where I want syncronized initialization with BOOST_HAS_THREADS not defined. And finally even if I build MT application it doesn't mean I want creation of this concrete singleton to be syncronized. And you enforce it.
8. No Meyer's singleton
What if do not want all this manager staff? What's "all this manager staff" and
I just want singleton. Don't care about it's distruction order. And don't need anyone to manage it.
OK, then just don't care and things just work. If you insist on Meyers' Singleton: Write it -- it's just a few lines .
That's true. But your framework need to support it as well. What If I decide that I do need to manage order of destruction of my singletons? Do I need to rewrite it completely now? Gennadiy

Gennadiy Rozental wrote:
Tobias Schwinger <tschwinger <at> isonews2.com> writes:
3. public construction and boost::restricted
I don't like this solution and very much prefer private constructor with friend declaration (especially if encapsulated into single macro). This will be a never ending source of confusion (what is boost::restricted, can I have restricted access, how do I create restricted instances etc) and doesn't really protect - once can still create instances of my class with valid C++ code. You're still free to use a private constructor and a friend declaration. Yes. But argue that you are trying to promote bad practice. Arguably. It works well to ensure the component is used as intended, it's brief and it optimizes out entirely.
No. It doesn't ensure that. One can still create instances of my class with valid C++. It's not brief implementation wise in comparison with doing nothing
which is error prone
and an alternative is as brief usage wise.
Further: Making friend with a template in another namespace does not work with a well-known and widely used compiler.
4. DLL support
Explanation of DLL issues in docs is very unclear. No examples provided. No tests showing that solution actually works. Accordingly I can't really comment on it, but from what I got I really doubt it. The test just hasn't been automated yet. And, yes, the documentation can use some improvement. As far as I can tell, simply there is no tests for this scenario. I probably didn't include it in the archive.
So you can't state it works for DLL. No one is able to verify.
No? I didn't know the people on this list are incapable of writing code!
Or do you expect us to believe your word?
Believe whatever you want ;-).
7. MT support
Setting aside mutexed and thread specific singletons covered above, regular singleton handling of MT is wrong as well. In simple words my primary complain: you can't use define based solution for switching MT/non MT. It should be template parameter. As of now there is no singleton that can work in presence of threads but without disregard to them. I can't get your point. There probably is none. I meant "without regard to them". IOW BOOST_HAS_THREADS is global compile time switch which should have no bearings in design on singleton. regardless of this flag I may or may not want instance construction to be syncronized. The design doesn't change based on that macro.
It does. You either do or don't do syncronization based on it.
Synchronisation with what? In a program with just one thread it's just a no-op. Regards, Tobias

you can't use define based solution for switching MT/non MT. It should be template parameter. As of now there is no singleton that can work in presence of threads but without [regard] to
Gennadiy wrote: them.
BOOST_HAS_THREADS is global compile time switch which should have no bearings in design on singleton. regardless of this flag I may or may not want instance construction to be syncronized.
Tobias wrote:
The design doesn't change based on that macro.
Gennadiy wrote:
It does. You either do or don't do syncronization based on it.
Tobias wrote:
Synchronisation with what? In a program with just one thread it's just a no-op.
This has been raised before. I normally write single-threaded code. Occasionally I am forced to write a worker thread to perform a particular function. That means that I need BOOST_HAS_THREADS defined. On the other hand, I /know/ that most of my singletons will only be used by the main thread, so why do I have to pay for synchronization on those singletons? -- Martin Bonner

Martin Bonner:
This has been raised before. I normally write single-threaded code. Occasionally I am forced to write a worker thread to perform a particular function. That means that I need BOOST_HAS_THREADS defined. On the other hand, I /know/ that most of my singletons will only be used by the main thread, so why do I have to pay for synchronization on those singletons?
This might be a relevant objection to the specific implementation under discussion, but I just want to point out that you don't need to pay for thread-safe initialization of function-level statics, especially in a "Singleton" context. Illustration: X* X::instance() { static X* s_px = 0; if( X* px = atomic_load_relaxed( &s_px ) ) { return px; // fast path } static X s_x; // "slow" thread-safe init atomic_store_release( &s_px, &s_x ); return s_px; } A sufficiently good compiler will fold this code into "static X s_x" so you won't need to do anything. The reason this works (except on Alpha) is that the accesses through the returned pointer are data-dependent and carry implicit acquire semantics.

Gennadiy Rozental:
Peter Dimov <pdimov <at> pdimov.com> writes:
X* X::instance() { static X* s_px = 0;
if( X* px = atomic_load_relaxed( &s_px ) )
&s_px doesn't look right here.
I'm using a C-style atomic interface for illustration purposes: T atomic_load_relaxed( T * pt ); // returns *pt, but atomically

On Jan 18, 2008 7:18 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Martin Bonner:
This has been raised before. I normally write single-threaded code. Occasionally I am forced to write a worker thread to perform a particular function. That means that I need BOOST_HAS_THREADS defined. On the other hand, I /know/ that most of my singletons will only be used by the main thread, so why do I have to pay for synchronization on those singletons?
This might be a relevant objection to the specific implementation under discussion, but I just want to point out that you don't need to pay for thread-safe initialization of function-level statics, especially in a "Singleton" context. Illustration:
X* X::instance() { static X* s_px = 0;
if( X* px = atomic_load_relaxed( &s_px ) ) { return px; // fast path }
static X s_x; // "slow" thread-safe init
atomic_store_release( &s_px, &s_x );
return s_px; }
Don't you need a mutex in the slow path to prevent two threads that both find s_ps null to try initialize s_x withoug mutual exclusion? Or are you assuming C++0x thread safe initialization of statics? In the latter case, isn't safe to assume that the compiler will already use a form of the above pattern anyway? BTW, slightly off-topic, will C++0x standardize load dependent memory barriers? According to the latest memory model paper, the then-current consensus was not to. gpd

Giovanni Piero Deretta: ...
Don't you need a mutex in the slow path to prevent two threads that both find s_ps null to try initialize s_x withoug mutual exclusion? Or are you assuming C++0x thread safe initialization of statics? In the latter case, isn't safe to assume that the compiler will already use a form of the above pattern anyway?
Yes, I'm assuming thread-safe initialization of s_x for illustration purposes. Yes, I hope that the compiler will use the above pattern. I'm just showing the proof of concept.
BTW, slightly off-topic, will C++0x standardize load dependent memory barriers? According to the latest memory model paper, the then-current consensus was not to.
I'm not sure what happened to N2359-N2361. N2342 lists them as active.

Tobias Schwinger <tschwinger <at> isonews2.com> writes:
No. It doesn't ensure that. One can still create instances of my class with valid C++. It's not brief implementation wise in comparison with doing nothing
which is error prone
What is error pronne?? Doing nothing?
and an alternative is as brief usage wise.
Further:
Making friend with a template in another namespace does not work with a well-known and widely used compiler.
4. DLL support
Explanation of DLL issues in docs is very unclear. No examples
We shouldn't based our desings/interfaces based on broken compilers. provided.
No
tests showing that solution actually works. Accordingly I can't really comment on it, but from what I got I really doubt it. The test just hasn't been automated yet. And, yes, the documentation can use some improvement. As far as I can tell, simply there is no tests for this scenario. I probably didn't include it in the archive.
So you can't state it works for DLL. No one is able to verify.
No? I didn't know the people on this list are incapable of writing code!
It's not my responsibility to do a unit testing for you. From where I stand any feature which is not backed up with unit test, can't be considerred supported.
Or do you expect us to believe your word?
Believe whatever you want .
I believe your library doesn't work for DLLs. And you didn't even provide a test to prove me wrong.
7. MT support
Setting aside mutexed and thread specific singletons covered above, regular singleton handling of MT is wrong as well. In simple words my primary complain: you can't use define based solution for switching MT/non MT. It should be template parameter. As of now there is no singleton that can work in presence of threads but without disregard to them. I can't get your point. There probably is none. I meant "without regard to them". IOW BOOST_HAS_THREADS is global compile time switch which should have no bearings in design on singleton. regardless of this flag I may or may not want instance construction to be syncronized. The design doesn't change based on that macro.
It does. You either do or don't do syncronization based on it.
Synchronisation with what? In a program with just one thread it's just a no-op.
As I said, I may want to do syncronization even if BOOST_HAS_THREADS is not defined (for example with coroutine based solutions). And what is more important I may not want to do it if BOOST_HAS_THREADS is defined. Your desing enforces these decisions for me. Gennadiy

Gennadiy Rozental wrote:
Tobias Schwinger <tschwinger <at> isonews2.com> writes:
No. It doesn't ensure that. One can still create instances of my class with valid C++. It's not brief implementation wise in comparison with doing nothing which is error prone
What is error pronne?? Doing nothing?
Yes.
and an alternative is as brief usage wise.
Further:
Making friend with a template in another namespace does not work with a well-known and widely used compiler.
We shouldn't based our desings/interfaces based on broken compilers.
> 4. DLL support > > Explanation of DLL issues in docs is very unclear. No examples provided. No > tests showing that solution actually works. Accordingly I can't really > comment on it, but from what I got I really doubt it. The test just hasn't been automated yet. And, yes, the documentation can use some improvement. As far as I can tell, simply there is no tests for this scenario. I probably didn't include it in the archive. So you can't state it works for DLL. No one is able to verify. No? I didn't know the people on this list are incapable of writing code!
It's not my responsibility to do a unit testing for you. From where I stand any feature which is not backed up with unit test, can't be considerred supported.
From where I stand testing is a minor concern as long as it's obvious that something /can/ work -- in dubio pro reo.
Or do you expect us to believe your word?
Believe whatever you want .
I believe your library doesn't work for DLLs. And you didn't even provide a test to prove me wrong.
The purpose of testing is not to prove anything -- it about detecting defects.
> 7. MT support > > Setting aside mutexed and thread specific singletons covered above, regular > singleton handling of MT is wrong as well. In simple words my primary > complain: you can't use define based solution for switching MT/non MT. It > should be template parameter. As of now there is no singleton that can work > in presence of threads but without disregard to them. I can't get your point. There probably is none. I meant "without regard to them". IOW BOOST_HAS_THREADS is global compile time switch which should have no bearings in design on singleton. regardless of this flag I may or may not want instance construction to be syncronized. The design doesn't change based on that macro. It does. You either do or don't do syncronization based on it.
Synchronisation with what? In a program with just one thread it's just a no-op.
As I said, I may want to do syncronization even if BOOST_HAS_THREADS is not defined (for example with coroutine based solutions). And what is more important I may not want to do it if BOOST_HAS_THREADS is defined. Your desing enforces these decisions for me.
OK, you might have a point there. Regards, Tobias

"Tobias Schwinger" <tschwinger@isonews2.com> wrote in message news:fmqifd$l3k$1@ger.gmane.org...
It's not my responsibility to do a unit testing for you. From where I stand any feature which is not backed up with unit test, can't be considerred supported.
From where I stand testing is a minor concern as long as it's obvious that something /can/ work -- in dubio pro reo.
Can you provide formal proof? Nothing is obvios to me. And without unit test is useless.
Or do you expect us to believe your word?
Believe whatever you want .
I believe your library doesn't work for DLLs. And you didn't even provide a test to prove me wrong.
The purpose of testing is not to prove anything -- it about detecting defects.
The purpose of unit testing is to prove that there are no defects and program/library/class works as expected. Gennadiy

Gennadiy Rozental wrote:
"Tobias Schwinger" <tschwinger@isonews2.com> wrote in message
The purpose of testing is not to prove anything -- it about detecting defects.
The purpose of unit testing is to prove that there are no defects and program/library/class works as expected.
Really? Can you *prove* that a software has no defects? There's no such thing as a bug free software. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

"Joel de Guzman" <joel@boost-consulting.com> wrote in message news:fmu1je$tq9$1@ger.gmane.org...
Gennadiy Rozental wrote:
"Tobias Schwinger" <tschwinger@isonews2.com> wrote in message
The purpose of testing is not to prove anything -- it about detecting defects.
The purpose of unit testing is to prove that there are no defects and program/library/class works as expected.
Really? Can you *prove* that a software has no defects? There's no such thing as a bug free software.
Obviously we can't prove-prove anything. But testing the other best thing we can do. It should give us assurance (or in other words be good enough proof) that software works as expected. Meditations like "it's obvious it can work" is no comparison. In software business it's more like "guilty until proven innocent". Gennadiy

Hi Tobias, how does Boost.Utility/Singleton solve the problem if the singleton calss itself needs arguments in its ctor (for instance if I want to use the RAII pattern)? best regards, Oliver

Kowalke Oliver (QD IT PA AS) wrote:
Hi Tobias, how does Boost.Utility/Singleton solve the problem if the singleton calss itself needs arguments in its ctor (for instance if I want to use the RAII pattern)?
Not at all, you have to solve it yourself. So reading from you post you have a class you can't (or don't want to) change, that needs arguments in the ctor. You can make a Singleton from that class using multiple inheritance. class a_singleton : public boost::singleton< a_singleton >, public my_class { a_singleton(boost::restricted) : my_class( /* args go here */ ) { } }; Parameterizing the static 'instance' method of a classic Singleton take is a bad idea IMO, because it causes redundancy all over the place. Regards, Tobias

On Jan 14, 2008 12:10 PM, John Torjo <john.groups@torjo.com> wrote:
* What is your evaluation of the design?
Not generic enough. It addresses a number of specific problems (e.g. use in MT contexts, order-of-initialisation fiasco, etc) but the author's design choices are neither customizable nor overridable. For instance, the design could be made more flexible by allowing thread-safety to be specified as a policy (with appropriate default) or by delegating the responsibility to the wrapped type. If BOOST_HAS_THREADS is defined, it looks as though I have no choice but to use mutexed instantiation and/or access. If I'm not interested in synchronised access, then the lease interface is useless. The solution to the OOI problem does not scale, and I would go as far as saying that it doesn't work in practice. In my experience, it's a constant maintenance nightmare to try and keep the various slot assignments in the correct order (I have to deal with a large number of singletons; yes that is a problem in and of itself - this library will do nothing to discourage it). The only scheme I've personally had any success with, so far, involves some form of reference counting, i.e. singletons that depend on other singletons do so explicitly (by incrementing the other's refcount on construction; the singletons are destroyed when their refcount goes to zero). Another reason why the proposed OOI solution fails in practice is that other singletons are not a singleton's only dependency: client code ( e.g. objects that reference the singleton) are dependencies as well and may affect the order of destruction. You just can't assume the singleton manager will be the last thing to go - there may be other globals. BTW I find the very idea of being able to "force" singleton destruction quite scary, but I haven't looked at the implementation details. The following sentence is also cause for concern: " Attempts to access an already destroyed Singleton instance cause the instance to be re-created." Is that true only for DLL usage? My biggest problem with this design is that it is unsuitable for library writers: types derived from typical singleton class designs, including boost::singleton and friends under review, invariably give rise to untestable code. To make a singleton's client code testable involves exposing some kind of overridable factory so that the singletonized type can be replaced with a test mockup. So far I have found this to be a hard problem to solve in general. Finally, this may constitute a minority opinion but I like to consider global access and single instance as orthogonal concepts. One may want to ensure a resource is only instantiated once without necessarily providing global access to that resource.
* What is your evaluation of the implementation?
Unnecessarily complex as a consequence of the design. If the functionality was layered, the code would be more readable. * What is your evaluation of the documentation?
It's OK although the DLL bit is unclear to me.
* What is your evaluation of the potential usefulness of the library?
I won't use it, but I command the author's attempt to provide a library for such a controversial design pattern. * Did you try to use the library? With what compiler?
Did you have any problems?
No. * How much effort did you put into your evaluation?
A glance? A quick reading? In-depth study?
I read the documentation, looked through the implementation and glanced at the tests. * Are you knowledgeable about the problem domain?
Yes.
And finally, every review should answer this question:
* Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion.
No. pj

Pierre-Jules Tremblay wrote: [snip]
My biggest problem with this design is that it is unsuitable for library writers: types derived from typical singleton class designs, including boost::singleton and friends under review, invariably give rise to untestable code. To make a singleton's client code testable involves exposing some kind of overridable factory so that the singletonized type can be replaced with a test mockup. So far I have found this to be a hard problem to solve in general.
Did you notice that it is possible to use multiple inheritance? This way you can implement and test your domain-specific logic as a "normal" class, and then just expose a singleton of that specific type using e.g. boost::singleton<>. / Johan

On Jan 16, 2008 2:29 AM, Johan Nilsson <r.johan.nilsson@gmail.com> wrote:
Pierre-Jules Tremblay wrote:
My biggest problem with this design is that it is unsuitable for library writers: types derived from typical singleton class designs, including boost::singleton and friends under review, invariably give rise to untestable code. To make a singleton's client code testable involves exposing some kind of overridable factory so that the singletonized type can be replaced with a test mockup. So far I have found this to be a hard problem to solve in general.
Did you notice that it is possible to use multiple inheritance? This way you can implement and test your domain-specific logic as a "normal" class, and then just expose a singleton of that specific type using e.g. boost::singleton<>.
Yes, it makes it possible to test the class to be wrapped as a singleton. That's the easy part. The hard part is to make the singleton's client code testable. If I have a singleton class A that wraps a "regular" class B, I can test B independently of A. However, I have no way to test any code that calls A::instance to get to B. pj

Pierre-Jules Tremblay wrote:
On Jan 16, 2008 2:29 AM, Johan Nilsson <r.johan.nilsson@gmail.com> wrote:
Pierre-Jules Tremblay wrote:
My biggest problem with this design is that it is unsuitable for library writers: types derived from typical singleton class designs, including boost::singleton and friends under review, invariably give rise to untestable code. To make a singleton's client code testable involves exposing some kind of overridable factory so that the singletonized type can be replaced with a test mockup. So far I have found this to be a hard problem to solve in general.
Did you notice that it is possible to use multiple inheritance? This way you can implement and test your domain-specific logic as a "normal" class, and then just expose a singleton of that specific type using e.g. boost::singleton<>.
Yes, it makes it possible to test the class to be wrapped as a singleton. That's the easy part. The hard part is to make the singleton's client code testable.
If I have a singleton class A that wraps a "regular" class B, I can test B independently of A. However, I have no way to test any code that calls A::instance to get to B.
That's why you should use dependency injection instead of designing the client code to directly call A::instance(). Why does the client code need to know it is accessing a singleton, when all it wants is the domain-specific logic? / Johan

Pierre-Jules, thank you for your review. Pierre-Jules Tremblay wrote:
On Jan 14, 2008 12:10 PM, John Torjo <john.groups@torjo.com> wrote:
* What is your evaluation of the design?
Not generic enough. It addresses a number of specific problems (e.g. use in MT contexts, order-of-initialisation fiasco, etc) but the author's design choices are neither customizable nor overridable.
For instance, the design could be made more flexible by allowing thread-safety to be specified as a policy (with appropriate default) or by delegating the responsibility to the wrapped type.
OK, FWIW policies complicate things. And what's their benefit here?
If BOOST_HAS_THREADS is defined, it looks as though I have no choice but to use mutexed instantiation and/or access. If I'm not interested in synchronised access, then the lease interface is useless.
Wrong: The lease interface is useful to improves performance. The test whether the Singleton has been initialized (which requires synchronization) can be performed only once.
The solution to the OOI problem does not scale, and I would go as far as saying that it doesn't work in practice. In my experience, it's a constant maintenance nightmare to try and keep the various slot assignments in the correct order (I have to deal with a large number of singletons; yes that is a problem in and of itself - this library will do nothing to discourage it).
You must have misunderstood the docs. OOI is not done with slots. The slots are to prevent unnecessary resurrection during destruction.
The only scheme I've personally had any success with, so far, involves some form of reference counting, i.e. singletons that depend on other singletons do so explicitly (by incrementing the other's refcount on construction; the singletons are destroyed when their refcount goes to zero).
You might have gotten away with it in practice, but introducing this kind of coupling seems really bad design to me.
Another reason why the proposed OOI solution fails in practice is that other singletons are not a singleton's only dependency: client code ( e.g. objects that reference the singleton) are dependencies as well and may affect the order of destruction.
What is the "proposed OOI solution" you are talking about?
You just can't assume the singleton manager will be the last thing to go - there may be other globals.
It's the "we should remove pointers from C++ because one can dereference NULL" kind-of argumentation.
BTW I find the very idea of being able to "force" singleton destruction quite scary, but I haven't looked at the implementation details.
It's necessary, as long as C++ runs on top of ABIs that don't support code to be run automatically when a dynamic library is unloaded and I can assure you that running code in an unloaded, dynamic library is a lot scarier :-).
The following sentence is also cause for concern: " Attempts to access an already destroyed Singleton instance cause the instance to be re-created." Is that true only for DLL usage?
It's true in general.
My biggest problem with this design is that it is unsuitable for library writers: types derived from typical singleton class designs, including boost::singleton and friends under review, invariably give rise to untestable code. To make a singleton's client code testable involves exposing some kind of overridable factory so that the singletonized type can be replaced with a test mockup. So far I have found this to be a hard problem to solve in general.
Interesting point.
Finally, this may constitute a minority opinion but I like to consider global access and single instance as orthogonal concepts. One may want to ensure a resource is only instantiated once without necessarily providing global access to that resource.
So Singletons should be dynamic arrays in your opinion? Regards, Tobias

"Tobias Schwinger" <tschwinger@isonews2.com> wrote in message news:fmkefr$cf3$1@ger.gmane.org...
For instance, the design could be made more flexible by allowing thread-safety to be specified as a policy (with appropriate default) or by delegating the responsibility to the wrapped type.
OK, FWIW policies complicate things. And what's their benefit here?
I disagree. In general policies promote modularization. In this concrete case policy based solution would allow more flexibility in how "thread-safe" I want to be.
If BOOST_HAS_THREADS is defined, it looks as though I have no choice but to use mutexed instantiation and/or access. If I'm not interested in synchronised access, then the lease interface is useless.
Wrong:
The lease interface is useful to improves performance. The test whether the Singleton has been initialized (which requires synchronization) can be performed only once.
The lease interface only improves preformance in your design. With Meyer's singleton instance() is as efficient. With any other solution that returns T&, I just need to store local referene to the target type. Gennadiy
The solution to the OOI problem does not scale, and I would go as far as saying that it doesn't work in practice. In my experience, it's a constant maintenance nightmare to try and keep the various slot assignments in the correct order (I have to deal with a large number of singletons; yes that is a problem in and of itself - this library will do nothing to discourage it).
You must have misunderstood the docs. OOI is not done with slots. The slots are to prevent unnecessary resurrection during destruction.
The only scheme I've personally had any success with, so far, involves some form of reference counting, i.e. singletons that depend on other singletons do so explicitly (by incrementing the other's refcount on construction; the singletons are destroyed when their refcount goes to zero).
You might have gotten away with it in practice, but introducing this kind of coupling seems really bad design to me.
Another reason why the proposed OOI solution fails in practice is that other singletons are not a singleton's only dependency: client code ( e.g. objects that reference the singleton) are dependencies as well and may affect the order of destruction.
What is the "proposed OOI solution" you are talking about?
You just can't assume the singleton manager will be the last thing to go - there may be other globals.
It's the "we should remove pointers from C++ because one can dereference NULL" kind-of argumentation.
BTW I find the very idea of being able to "force" singleton destruction quite scary, but I haven't looked at the implementation details.
It's necessary, as long as C++ runs on top of ABIs that don't support code to be run automatically when a dynamic library is unloaded and I can assure you that running code in an unloaded, dynamic library is a lot scarier :-).
The following sentence is also cause for concern: " Attempts to access an already destroyed Singleton instance cause the instance to be re-created." Is that true only for DLL usage?
It's true in general.
My biggest problem with this design is that it is unsuitable for library writers: types derived from typical singleton class designs, including boost::singleton and friends under review, invariably give rise to untestable code. To make a singleton's client code testable involves exposing some kind of overridable factory so that the singletonized type can be replaced with a test mockup. So far I have found this to be a hard problem to solve in general.
Interesting point.
Finally, this may constitute a minority opinion but I like to consider global access and single instance as orthogonal concepts. One may want to ensure a resource is only instantiated once without necessarily providing global access to that resource.
So Singletons should be dynamic arrays in your opinion?
Regards, Tobias
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Gennadiy Rozental wrote:
"Tobias Schwinger" <tschwinger@isonews2.com> wrote in message news:fmkefr$cf3$1@ger.gmane.org...
For instance, the design could be made more flexible by allowing thread-safety to be specified as a policy (with appropriate default) or by delegating the responsibility to the wrapped type. OK, FWIW policies complicate things. And what's their benefit here?
I disagree. In general policies promote modularization. In this concrete case policy based solution would allow more flexibility in how "thread-safe" I want to be.
They often also promote over-complication: Thread-safety that is more complex than applying a simple mutex is very case-dependent and should be implemented manually.
If BOOST_HAS_THREADS is defined, it looks as though I have no choice but to use mutexed instantiation and/or access. If I'm not interested in synchronised access, then the lease interface is useless. Wrong:
The lease interface is useful to improves performance. The test whether the Singleton has been initialized (which requires synchronization) can be performed only once.
The lease interface only improves preformance in your design. With Meyer's singleton instance() is as efficient. With any other solution that returns T&, I just need to store local referene to the target type.
Storing the instance is out of the question with automatic locking. [... tons of text] http://learn.to/quote Regards, Tobias

Tobias Schwinger <tschwinger <at> isonews2.com> writes:
Gennadiy Rozental wrote:
"Tobias Schwinger" <tschwinger <at> isonews2.com> wrote in message news:fmkefr$cf3$1 <at> ger.gmane.org...
For instance, the design could be made more flexible by allowing thread-safety to be specified as a policy (with appropriate default) or by delegating the responsibility to the wrapped type. OK, FWIW policies complicate things. And what's their benefit here?
I disagree. In general policies promote modularization. In this concrete case policy based solution would allow more flexibility in how "thread-
safe"
I want to be.
They often also promote over-complication:
Thread-safety that is more complex than applying a simple mutex is very case-dependent and should be implemented manually.
If BOOST_HAS_THREADS is defined, it looks as though I have no choice but to use mutexed instantiation and/or access. If I'm not interested in synchronised access, then the lease interface is useless. Wrong:
The lease interface is useful to improves performance. The test whether the Singleton has been initialized (which requires synchronization) can be performed only once.
The lease interface only improves preformance in your design. With Meyer's singleton instance() is as efficient. With any other solution that returns T&, I just need to store local referene to the target type.
Storing the instance is out of the question with automatic locking.
No. This is not true. If I use singleton<sincronized<T> >, instance method returns syncronized<T>& and access is syncronized. But promoting automated locking of all the class methods is bad idea as well IMO. This is strait road to deadlocks. I'd prefer syncronization to be implemented as part of class T, which knows specifically what to syncronize. If I want to have some kind of automation, I may go with something like this, for example: A : singleton<syncronize_IO<A> >. singleton should suppport this usage. Gennadiy

On Jan 16, 2008 3:15 AM, Tobias Schwinger <tschwinger@isonews2.com> wrote:
thank you for your review.
You are most welcome. Thank you for your response to my comments.
For instance, the design could be made more flexible by allowing thread-safety to be specified as a policy (with appropriate default) or by delegating the responsibility to the wrapped type.
OK, FWIW policies complicate things. And what's their benefit here?
In some cases, policies do complicate things. For instance, while I have marveled at the Loki Singleton implementation, it is at one extreme of the general-purpose design spectrum and I'm not willing to pay the price (in complexity). I find your design is, on the other hand, at the special-purpose end of that spectrum, and I'm not sure that's necessary.
If BOOST_HAS_THREADS is defined, it looks as though I have no choice but to use mutexed instantiation and/or access. If I'm not interested in synchronised access, then the lease interface is useless.
Wrong:
The lease interface is useful to improves performance. The test whether the Singleton has been initialized (which requires synchronization) can be performed only once.
The test whether the Singleton has been initialized does not require synchronisation if you are not in an MT context or if the MT context is handled elsewhere in the design. The performance improvement is nil when compared to Meyer's singleton, which is the obvious choice in a single-thread context. What I'm asking for is the opportunity to select the simplest, most efficient implementation I can get away with while keeping the interface generic. I see another argument in favour of a "customizable" synchronisation mechanism: potential for deadlocks. If there are any circular dependencies between singletons then you need some kind of lock restriction mechanism to catch them. You may tell me that having singletons depend on each other this way is "bad design" and you would be right, but bad designs are part of life ;-) In practice, I find that as soon as you allow singletons to creep into a design, they start to depend on each other.
The solution to the OOI problem does not scale, and I would go as far as saying that it doesn't work in practice. In my experience, it's a constant maintenance nightmare to try and keep the various slot assignments in the correct order (I have to deal with a large number of singletons; yes that is a problem in and of itself - this library will do nothing to discourage it).
You must have misunderstood the docs. OOI is not done with slots. The slots are to prevent unnecessary resurrection during destruction.
Okay, I should have said "OOD" (order of destruction) instead. So reading the documentation: Singleton instances are normally destroyed in reverse order of their construction, that is for a group of Singletons with their integral DisposalSlot template arguments being equal, where the destruction of these groups is ordered by the ascending DisposalSlot values. We could raise the DisposalSlot value of global_log from the previous examples to make sure it outlives other singletons that use 0 (the default): (...) That, to me, sounds like the slot mecanism is for handling dependencies, in which case one must be careful in selecting which singletons fit in which slot.
The only scheme I've personally had any success with, so far, involves some form of reference counting, i.e. singletons that depend on other singletons do so explicitly (by incrementing the other's refcount on construction; the singletons are destroyed when their refcount goes to zero).
You might have gotten away with it in practice, but introducing this kind of coupling seems really bad design to me.
The coupling is there anyways (in the singleton's client code), but it is only implicit: that's the problem with global variables and singletons are no different in that respect. What I described only makes the coupling explicit in the singleton's interface. It's not as bad as it may sound: think shared_ptr with a forward declaration of the single-instanced type.
Another reason why the proposed OOI solution fails in practice is that other singletons are not a singleton's only dependency: client code ( e.g. objects that reference the singleton) are dependencies as well and may affect the order of destruction.
What is the "proposed OOI solution" you are talking about?
Yours, although it appears I had mislabeled it. I'll think up a concrete example and write back.
You just can't assume the singleton manager will be the last thing to go - there may be other globals.
It's the "we should remove pointers from C++ because one can dereference NULL" kind-of argumentation.
That's a little unfair, but I think I see what you mean. In that case, I think you need to improve the documentation to clearly express the limitations of the design, e.g. "singletons cannot have dependencies on globals or singletons not of this library, and vice-versa".
BTW I find the very idea of being able to "force" singleton destruction quite scary, but I haven't looked at the implementation details.
It's necessary, as long as C++ runs on top of ABIs that don't support code to be run automatically when a dynamic library is unloaded and I can assure you that running code in an unloaded, dynamic library is a lot scarier :-).
Admittedly, I haven't had to deal with that use case in a long time, so I probably shouldn't comment on it.
Finally, this may constitute a minority opinion but I like to consider global access and single instance as orthogonal concepts. One may want to ensure a resource is only instantiated once without necessarily providing global access to that resource.
So Singletons should be dynamic arrays in your opinion?
I'm not sure what you mean, and I haven't had coffee yet so perhaps that's why ;-). How do dynamic arrays help separate the concepts of preventing a second instantiation and global access to the first instance? Cheers, pj

Pierre-Jules Tremblay wrote:
On Jan 16, 2008 3:15 AM, Tobias Schwinger <tschwinger@isonews2.com> wrote:
thank you for your review.
You are most welcome. Thank you for your response to my comments.
Thanks again. This one was an interesting read, too.
For instance, the design could be made more flexible by allowing thread-safety to be specified as a policy (with appropriate default) or by delegating the responsibility to the wrapped type. OK, FWIW policies complicate things. And what's their benefit here?
In some cases, policies do complicate things. For instance, while I have marveled at the Loki Singleton implementation, it is at one extreme of the general-purpose design spectrum and I'm not willing to pay the price (in complexity).
Yep. I did my best to avoid a Loki-style design.
The solution to the OOI problem does not scale, and I would go as far as saying that it doesn't work in practice. In my experience, it's a constant maintenance nightmare to try and keep the various slot assignments in the correct order (I have to deal with a large number of singletons; yes that is a problem in and of itself - this library will do nothing to discourage it). You must have misunderstood the docs. OOI is not done with slots. The slots are to prevent unnecessary resurrection during destruction.
Okay, I should have said "OOD" (order of destruction) instead. So reading the documentation:
Singleton instances are normally destroyed in reverse order of their construction, that is for a group of Singletons with their integral DisposalSlot template arguments being equal, where the destruction of these groups is ordered by the ascending DisposalSlot values. We could raise the DisposalSlot value of global_log from the previous examples to make sure it outlives other singletons that use 0 (the default): (...)
That, to me, sounds like the slot mecanism is for handling dependencies, in which case one must be careful in selecting which singletons fit in which slot.
Well, it's a means to override a default behavior that should just work in a majority of cases: o Reverse order of construction, and o resurrection.
Finally, this may constitute a minority opinion but I like to consider global access and single instance as orthogonal concepts. One may want to ensure a resource is only instantiated once without necessarily providing global access to that resource. So Singletons should be dynamic arrays in your opinion?
I'm not sure what you mean, and I haven't had coffee yet so perhaps that's why ;-). How do dynamic arrays help separate the concepts of preventing a second instantiation and global access to the first instance?
They allow more instances at one global access point. Regards, Tobias

Tobias, Does it support a single singleton across multiple DLL's? I.e., singleton S is accessed the first time by DLL A (and is created), then it is accessed by DLL B. Does DLL B create a new instance of singleton S for it, or can it use the one created by DLL A as a truly global singleton? Thanks, Edson

Edson Tadeu wrote:
Tobias,
Does it support a single singleton across multiple DLL's? I.e., singleton S is accessed the first time by DLL A (and is created), then it is accessed by DLL B. Does DLL B create a new instance of singleton S for it, or can it use the one created by DLL A as a truly global singleton?
Yes. See the documentation for details. Regards, Tobias

Tobias Schwinger wrote:
Edson Tadeu wrote:
Tobias,
Does it support a single singleton across multiple DLL's? I.e., singleton S is accessed the first time by DLL A (and is created), then it is accessed by DLL B. Does DLL B create a new instance of singleton S for it, or can it use the one created by DLL A as a truly global singleton?
Yes. See the documentation for details.
Unless you have updated the documentation since the announcement, I think it would be a good idea to explain this in better detail. An 'implementation details' section would be a great addition to the document. Regards, Johan

Johan Nilsson wrote:
Tobias Schwinger wrote:
Edson Tadeu wrote:
Tobias,
Does it support a single singleton across multiple DLL's? I.e., singleton S is accessed the first time by DLL A (and is created), then it is accessed by DLL B. Does DLL B create a new instance of singleton S for it, or can it use the one created by DLL A as a truly global singleton? Yes. See the documentation for details.
Unless you have updated the documentation since the announcement, I think it would be a good idea to explain this in better detail. An 'implementation details' section would be a great addition to the document.
OK, I'll take this as the "how does it work"-question :-). It's actually quite easy: The macros introduce a member function that is defined in compiled code and used to access the Singleton. This way, all code to manage a Singleton's lifetime is in one place. The SubsystemTag works even simpler: It just changes the symbol names so multiple independent "families" of Singltons can coexist in one program. It is important, because otherwise the main program's infrastructure may "adopt" a Singleton of a dynamic library which will crash the program if the library got unloaded before termination. Regards, Tobias

From: Tobias Schwinger
Johan Nilsson wrote:
Tobias Schwinger wrote:
Edson Tadeu wrote:
Does it support a single singleton across multiple DLL's? I.e., singleton S is accessed the first time by DLL A (and is created), then it is accessed by DLL B. Does DLL B create a new instance of singleton S for it, or can it use the one created by DLL A as a truly global singleton? Yes. See the documentation for details.
Unless you have updated the documentation since the announcement, I think it would be a good idea to explain this in better detail. An 'implementation details' section would be a great addition to the document.
OK, I'll take this as the "how does it work"-question :-).
It's actually quite easy: The macros introduce a member function that is defined in compiled code and used to access the Singleton. This way, all code to manage a Singleton's lifetime is in one place.
I haven't looked at the library, but I don't understand how that works on Windows. Won't both DLLs have their own copy of the compiled code, and hence won't they both have their own copy of the singleton? -- Martin Bonner Senior Software Engineer/Team Leader PI SHURLOK LTD Telephone: +44 1223 441434 / 203894 (direct) Fax: +44 1223 203999 Email: martin.bonner@pi-shurlok.com www.pi-shurlok.com disclaimer

Martin Bonner wrote:
From: Tobias Schwinger
Johan Nilsson wrote:
Edson Tadeu wrote:
Does it support a single singleton across multiple DLL's? I.e., singleton S is accessed the first time by DLL A (and is created), then it is accessed by DLL B. Does DLL B create a new instance of singleton S for it, or can it use the one created by DLL A as a truly global singleton? Yes. See the documentation for details. Unless you have updated the documentation since the announcement, I
Tobias Schwinger wrote: think it would be a good idea to explain this in better detail. An 'implementation details' section would be a great addition to the document. OK, I'll take this as the "how does it work"-question :-).
It's actually quite easy: The macros introduce a member function that is defined in compiled code and used to access the Singleton. This way, all code to manage a Singleton's lifetime is in one place.
I haven't looked at the library, but I don't understand how that works on Windows. Won't both DLLs have their own copy of the compiled code, and hence won't they both have their own copy of the singleton?
No. Only one DLL has the code and the other one calls it. That is, given an appropriate .def file or 'declspec'ing of the class and correct usage of the placement macros. Regads, Tobias

Martin Bonner <Martin.Bonner <at> pi-shurlok.com> writes:
I haven't looked at the library, but I don't understand how that works on Windows. Won't both DLLs have their own copy of the compiled code, and hence won't they both have their own copy of the singleton?
I have exacly the same concern. From what I understand There is no way to export static member variable of the template. So I can't understand how it can "support DLLs". Gennadiy

On Jan 17, 2008 2:15 AM, Johan Nilsson <r.johan.nilsson@gmail.com> wrote:
Did you notice that it is possible to use multiple inheritance? This way you can implement and test your domain-specific logic as a "normal" class, and then just expose a singleton of that specific type using e.g. boost::singleton<>.
Yes, it makes it possible to test the class to be wrapped as a singleton. That's the easy part. The hard part is to make the singleton's client code testable.
If I have a singleton class A that wraps a "regular" class B, I can test B independently of A. However, I have no way to test any code that calls A::instance to get to B.
That's why you should use dependency injection instead of designing the client code to directly call A::instance(). Why does the client code need to know it is accessing a singleton, when all it wants is the domain-specific logic?
I agree and advocate for dependency injection myself. But your original comment was that somehow Tobias' singleton's multiple-inheritance support makes it possible to test the code. I'm saying it only enables you to test the class-to-be-used-as-a-singleton's code, not the client code. Now you're saying the client code shouldn't depend on the class being used as a singleton. I agree, but Tobias' design doesn't make that use case possible, so what are you suggesting (in the context of this particular review)? pj

Pierre-Jules Tremblay wrote:
On Jan 17, 2008 2:15 AM, Johan Nilsson <r.johan.nilsson@gmail.com> wrote:
Did you notice that it is possible to use multiple inheritance? This way you can implement and test your domain-specific logic as a "normal" class, and then just expose a singleton of that specific type using e.g. boost::singleton<>.
Yes, it makes it possible to test the class to be wrapped as a singleton. That's the easy part. The hard part is to make the singleton's client code testable.
If I have a singleton class A that wraps a "regular" class B, I can test B independently of A. However, I have no way to test any code that calls A::instance to get to B.
That's why you should use dependency injection instead of designing the client code to directly call A::instance(). Why does the client code need to know it is accessing a singleton, when all it wants is the domain-specific logic?
I agree and advocate for dependency injection myself. But your original comment was that somehow Tobias' singleton's multiple-inheritance support makes it possible to test the code. I'm saying it only enables you to test the class-to-be-used-as-a-singleton's code, not the client code.
Exactly. I never said that MI somehow magically enables you to test the client code. It can help, though.
Now you're saying the client code shouldn't depend on the class being used as a singleton.
Yes. The client code should depend on the "class-to-be-used-as-a-singleton". Example: class Foo {}; class FooSingleton : public Foo, public singleton<FooSingleton, ...> {}; Unit-test Foo as normal and make clients depend on Foo rather than FooSingleton. If you need to use e.g. "lease", design an adapter interface or concept (depending on whether you want to use dynamic or static polymorphism) that mirrors that behaviour and make clients depend on that instead.
I agree, but Tobias' design doesn't make that use case possible,
I wouldn't say that the particular use case is impossible, possibly awkward. See above.
so what are you suggesting (in the context of this particular review)?
This is getting off-topic I think, so I won't disturb the review by further comments on testability. I guess that what I'm saying is that code that uses singletons are testable, even without the "settable singleton" variety, as long as one carefully designs the client code not to directly access the singleton; i.e. don't call singleton::instance(). Note that when using static polymorphism you could even allow clients to directly call singleton::instance(), as long as singletons' type is a template parameter for the client. / Johan

|- boost::singleton| : can be used to create Singletons with synchronized initialization.
I've just become aware that g++ already provides synchronised initialisation of function-scope statics, unless you specify -fno-threadsafe-statics, and that if N2444 is accepted this will be the required behaviour in C++0x. With this functionality, there is no need for the proposed boost::singleton class since Meyer's singleton suffices: class MyClass { MyClass() {...}; public: static MyClass& instance() { static MyClass i; return i; } }; What do people feel about implementing functionality in a Boost library that will soon become unnecessary? I previously suggested that we could have a safe_static<T> template or macro, but I'm now wondering if we really want unsafe_static<T> to get the opposite effect! Neither is simple to implement; a macro like this perhaps: #define UNSAFE_STATIC(T,t) // The compiler would add unwanted locking if we just wrote 'static T t'. // So we declare uninitialised memory to hold t, and code our own initialisation test. static char _#t#_buf [sizeof(T)]; // worry about alignment static bool _#t#_init = false; if (!_#t#_init) { new (&_#t#_buf[0]) T; _#t#_init = true; } T& t = *(???_cast<T*>(&_#t#_buf[0])); Tobias, since I wrote my review I've seen a few others also suggesting that you should decouple the thread-safety features (e.g. the synchronous access in your mutex_singleton) from the singleton itself. I would be interested to know whether you would consider doing this in a revision of your submission, or whether you want to stick to your existing implementation. Regards, Phil.

Phil Endecott wrote:
|- boost::singleton| : can be used to create Singletons with synchronized initialization.
I've just become aware that g++ already provides synchronised initialisation of function-scope statics, unless you specify -fno-threadsafe-statics, and that if N2444 is accepted this will be the required behaviour in C++0x. With this functionality, there is no need for the proposed boost::singleton class since Meyer's singleton suffices:
I'm aware of the ABI improvements. I'm also aware that GCC4 has #pragma GCC visibility ... (or so) which lets us turn off symbol merging (and is nonstandard). Pretty cool stuff (and makes SubsystemTag unnecessary). Meyers' Singleton does not suffice in all cases. And C++0x is far future given that many compilers that are in use today don't even speak C++98.
Tobias, since I wrote my review I've seen a few others also suggesting that you should decouple the thread-safety features (e.g. the synchronous access in your mutex_singleton) from the singleton itself. I would be interested to know whether you would consider doing this in a revision of your submission, or whether you want to stick to your existing implementation.
I'm afraid that in the foreseeable future there won't be enough spare time in one piece for me to get it done. Regards, Tobias

John Torjo wrote:
Hi all,
Today starts the formal Fast-Track review of the Boost.Utility/Singleton library. This is a very useful utility, so I'm expecting lots of reviews ;)
Singleton is a useful pattern and a library that makes it easier to create singletons that work properly under all circumstances is also useful. I am using this library slightly modified to fix compiler errors and warnings from the Vault in production code. I have some performance concerns about on demand initialization. In general I initialize and destroy my singletons deterministically early in main and skip the initialized check for every access. Some people have mentioned Meyer's singleton as an option to skip the initialized check but doesn't the compiler generally just insert that same logic for you for function local statics? The thread safety granularity is wrong. I need to be able to create singletons that I know will only be used from one thread of a multi-threaded program without the overhead of synchronization. The ability to explicitly destroy all the singletons is crucial to my environment where destructors for objects with static duration are not called during program shutdown. The proposed Singleton library provides an easy solution for this requirement which works well for me. I see some overlap between Boost.Pool and the proposed Boost.Singleton and if a Singleton library gets accepted into boost I'd like to see Pool use Singleton. I vote to not accept this library at this time because of the thread safety granularity issues. Thanks, Michael Marcin
participants (17)
-
Anthony Williams
-
dherring@ll.mit.edu
-
Edson Tadeu
-
Frank Mori Hess
-
Frank Mori Hess
-
Gennadiy Rozental
-
Giovanni Piero Deretta
-
Joel de Guzman
-
Johan Nilsson
-
John Torjo
-
Kowalke Oliver (QD IT PA AS)
-
Martin Bonner
-
Michael Marcin
-
Peter Dimov
-
Phil Endecott
-
Pierre-Jules Tremblay
-
Tobias Schwinger