
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