A much better way of doing Singleton's (updated!)

A place for Ogre users to discuss non-Ogre subjects with friends from the community.
User avatar
JohnJ
OGRE Expert User
OGRE Expert User
Posts: 975
Joined: Thu Aug 04, 2005 4:14 am
Location: Santa Clara, California
x 4

A much better way of doing Singleton's (updated!)

Post by JohnJ »

Is it just me, or is the way Ogre and a lot of other libraries implement singletons really awkward, tedious, and error prone? For example, to use singletons you have to type something like this:

Code: Select all

MyClass::getSingleton().doStuff();
It gets worse if you have to check if a singleton is initialized if this isn't guaranteed all the time:

Code: Select all

if (MyClass::getSingletonPtr() != NULL) MyClass::getSingleton().doStuff();
Not only is this tedious and error prone to type, but it often makes lines get so long I have to scroll or make them multiline due to the "::getSingleton()."'s taking up so much space.

I've recently made a simple effective, safe, and powerful class helper for adding singletons that allows you to access them very easily:

Code: Select all

MyClass->doStuff();
if (MyClass != NULL) MyClass->doStuff();
if (MyClass) MyClass->doStuff();
Additionally, it allows you to have full control over construction:

Code: Select all

MyClass = new Singleton::MyClass();
As well as destruction if you like (although it will automatically deleted when the program shuts down anyway):

Code: Select all

MyClass = NULL;
It's basically implemented as a form of smart pointer, designed specifically for singletons making it safe and easy to use for this. It's also very easy to make a class into a singleton with this method - just two lines need to be added - and you don't even have to modify the class itself.

Why don't more people use a method like this? The method used by Ogre for example is tedious, error prone, and takes a lot more typing effort overall. As far as I can tell the only flaw with this method is that it makes singletons too easy, since it's not good to use singletons too much, but this is no excuse for a bad singleton implementation :).

I guess maybe you could argue that the "getSingleton()" notation makes it explicitly clear that you're using a singleton, but so does my method: if you use the naming convention where class names are always capitalized, and functions/variables always begin in lower case, there will never be any confusion with the examples shown above since C++ does not support "MyClass->functionCall();" and it could not possibly be interpreted as anything but a singleton. Even if you use another naming convention, you can still use prefixes to distinguish singletons.

Edit: Here is the full file & documentation (SmartSingleton.h):

Code: Select all

/* Copyright (c) 2009 John Judnich

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.

3. This notice may not be removed or altered from any source
distribution.
*/

#ifndef _SMARTSINGLETON_H__
#define _SMARTSINGLETON_H__

//----------------------------------------------------------------------------------------------
// Documentation

/** \brief A powerful, no overhead (inline), easy to use, safe, hassle free singleton implementation helper.

Primarily, this class was intended to eliminate the use of the tedious "MyClass::getSingleton()."
notation often used, but also offers other time saving and safety features. Internally it's
not much more than a vague form of safe/smart pointer designed specially for singletons.

Using SmartSingleton's also allows you to define class singletons easily without modifying your
class definitons (allowing easy "singleton-ization" or "de-singleton-ization"). It also enables
the use of non-singleton instances of the same class if you want to do this.

Instructions on how to use a SmartSingleton will be described below, but first some examples
showing how it's used:

Initializing a singleton instance is extremely easy. Example:
"MyClass = new Singleton::MyClass();"

Using the singleton is even easier:
"MyClass->functionCall();"
"MyClass->doStuff();"

The singleton instance will be automatically deleted when your program shuts down. However,
if you need to delete the instance at a certain time, this is extremely easy:
"MyClass = NULL;"

You can also check if you've initialized an instance. Examples:
"if (MyClass != NULL) { ... }"
"if (MyClass) { ... }"

Implementing your classes using SmartSingleton required very minor changes. Here is one example:

//-- MyFile.h --
...
namespace Singleton //<-- move your singleton classes into this namespace
{
class MyClass
{
...
};
}
extern SmartSingleton<Singleton::MyClass> MyClass; //<-- add this to your singleton class header file
...

//-- MyFile.cpp --
...
SmartSingleton<Singleton::MyClass> MyClass; //<-- add this to your singleton class source file
...

Basically it just involves defining a SmartSingleton variable that will eventually hold
an instance of your class when you set "MyClass = new Singleton::MyClass();" or whatever.

Note that when you assign a singleton instance, it will intentionally generate an error
if you assign like "MyClass = pointerToSingletonInstance;" This is not allowed since the
SmartSingleton automatically deletes the instance, and you keeping a pointer of it is not only
useless but misleading (for example you might out of habit call "delete pointerToSingletonInstance;",
which will always cause your program to crash at some point).

Note that this is just an example implementation, so you can organize or use the SmartSingleton
variable however you like. For example, if you prefer to name the SmartSingleton variable with a
prefix or something to explicitly identify it is a singleton, this is your choice (and it would
eliminate the need to put the actual class implementation within a Singleton namespace to avoid
a clash).

That said, if you use the naming convention where class names are always capitalized, and
functions/variables always begin in lower case, there will never be any confusion with the example
technique above since C++ does not support "MyClass->functionCall();" and it could not possibly be
interpreted as anything but a singleton.

Advanced: Defining SMARTSINGLETON_STATIC (recommended method is to uncomment the appropriate line
in SmartSingleton.h) will set a variation of SmartSingleton to be used which allocates the singleton
instance statically (at compile time) rather than dynamically. This prevents the need
for your singletons to consume memory in the dynamic heap, which may be desirable.

The interface of the variation is identical to the standard SmartSingleton, so nothing else
needs to be changed to use it except your singleton class must have a default constructor.

It is recommended that the default constructor do little or nothing if you intend to
assign the singleton using "new MyClass()" to avoid double initialization. Just remember
that the class destructor (if any) must be able to run on even an empty object without
crashing.

If your singleton class contains a large amount of raw data like arrays (pointers to arrays
are fine of course), etc., it is recommended to avoid initializing it using "new MyClass()"
since assigning in this way requires that the data be copied from the given object into
static memory. Instead consider using an "initialize()" member function. However, in most
cases this will not be necessary.
*/

//----------------------------------------------------------------------------------------------

static void SmartSingleton_BadInstantiation()
{
	throw std::logic_error("SmartSingleton error: Bad instantiation - you may only instantiate a singleton class once.");
	/* If you program is crashing here, then somewhere in your code you are defining or instantiating
	a singleton illegally (more than once). */
}

//#define SMARTSINGLETON_STATIC

#ifndef SMARTSINGLETON_STATIC
template <class T>
class SmartSingleton
{
private:
	static T *instance;

public:
	SmartSingleton()
	{
		if (instance != NULL)
			SmartSingleton_BadInstantiation();
	}

	~SmartSingleton()
	{
		if (instance != NULL)
			delete instance;
	}

	///See class documentation for examples of use of the "=" operator.
	inline SmartSingleton& operator=(T *ptr)
	{
		if (ptr != NULL) {
			if (instance != NULL)
				SmartSingleton_BadInstantiation();
			instance = ptr;
		} else {
			delete instance;
			instance = ptr;
		}
		return *this;
	}

	//This should make it impossible to set to an lvalue, which is not allowed for safety
	inline SmartSingleton& operator=(T *&ptr)
	{
		ptr = NULL;
		throw std::logic_error("Internal error!"); //Function should never compile to execute
	}

	inline T& operator*() const { assert(instance); return *instance; }
	inline T* operator->() const { assert(instance); return instance; }

	bool operator==(const T *other) const { return (instance == other); }
	bool operator!=(const T *other) const { return (instance != other); }
	operator bool() { return (instance != NULL); }
};
template <class T> T *SmartSingleton<T>::instance = NULL;
#endif

#ifdef SMARTSINGLETON_STATIC
template <class T>
class SmartSingleton
{
private:
	static T staticInstance;
	static bool instantiated;

public:
	SmartSingleton()
	{
		if (instantiated)
			SmartSingleton_BadInstantiation();
	}

	~SmartSingleton()
	{
		staticInstance.~T();
		staticInstance = T();
		instantiated = false;
	}

	///See class documentation for examples of use of the "=" operator.
	inline SmartSingleton& operator=(T *ptr)
	{
		if (ptr != NULL) {
			if (instantiated)
				SmartSingleton_BadInstantiation();
			staticInstance = *ptr;
			*ptr = T();
			delete ptr;
			instantiated = true;
		} else {
			staticInstance.~T();
			staticInstance = T();
			instantiated = false;
		}
		return *this;
	}

	//This should make it impossible to set to an lvalue, which is not allowed for safety
	inline SmartSingleton& operator=(T *&ptr)
	{
		ptr = NULL;
		throw std::logic_error("Internal error!"); //Function should never compile to execute
	}

	inline T& operator*() const { assert(instantiated); return staticInstance; }
	inline T* operator->() const { assert(instantiated); return &staticInstance; }

	bool operator==(const T *other) const { return (other == NULL ? !instantiated : instantiated); }
	bool operator!=(const T *other) const { return (other != NULL ? !instantiated : instantiated); }
	operator bool() { return instantiated; }
};
template <class T> T SmartSingleton<T>::staticInstance;
template <class T> bool SmartSingleton<T>::instantiated = false;
#endif


///This macro can be inserted at the top of your constructor to ensure that only one instance
///is ever created:
#define ENFORCE_SINGLETON_CONSTRUCTION \
	static bool ____instantiated = false; \
	if (____instantiated) SmartSingleton_BadInstantiation(); \
	____instantiated = true;


#endif
Last edited by JohnJ on Tue Jul 07, 2009 11:29 pm, edited 4 times in total.
User avatar
steven
Gnoll
Posts: 657
Joined: Mon Feb 28, 2005 1:53 pm
Location: Australia - Canberra (ex - Switzerland - Geneva)
Contact:

Re: A *much* better way of doing Singleton's (IMO)

Post by steven »

JohnJ wrote:Why don't more people use a method like this?
Perhaps because they don't see how you achieve it :mrgreen:

[EDIT]Thanks for adding the code[/EDIT] Would you mind showing us how you did it?

What would happen if someone new to your library did:

Code: Select all

MyClass class = new MyClass();
Last edited by steven on Wed Jul 08, 2009 2:26 am, edited 1 time in total.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: A *much* better way of doing Singleton's (IMO)

Post by nullsquared »

JohnJ wrote: Why don't more people use a method like this?
Because it takes singletons and makes them even more implicit than they already are. Don't use singletons, they're worthless and error-prone.
User avatar
JohnJ
OGRE Expert User
OGRE Expert User
Posts: 975
Joined: Thu Aug 04, 2005 4:14 am
Location: Santa Clara, California
x 4

Re: A *much* better way of doing Singleton's (IMO)

Post by JohnJ »

steven: I'll probably release it for free soon, I'm just wasted some feedback from various people on the idea first :)
steven wrote:What would happen if someone new to your library did:

Code: Select all

MyClass class = new MyClass();
My compiler gives: "Syntax error: identifier 'MyClass'".

If you wanted to create a local instance of the class as a non-singleton, there is technically a way, but you wouldn't want to do that anyway because then it's not really a singleton any more (and it's confusing).
Because it takes singletons and makes them even more implicit than they already are.
Did you read the last paragraph of my first post? I already proved this argument is wrong. I'll summarize: My technique is just as explicitly obvious that it's a singleton as Ogre's implementation, unless your definition of "explicit" includes a requirement for 15 characters of explicitness every time it's used. But by that logic though, you could claim that "object->member" notation is bad because it's "less explicit" than "(*object).member".
Don't use singletons, they're worthless and error-prone.
I didn't think I would have to state the obvious here: This isn't a debate about where and why singletons should or shouldn't be used. It's about what's the best implementation, in the event a singleton is necessary for whatever reason there may be.

I agree that singletons should not be used unless absolutely necessary. But, if you want to debate where and why singletons should or shouldn't be used, please start a new thread and I'll be happy to elaborate my views on the matter :).
Last edited by JohnJ on Sat Jul 04, 2009 3:34 am, edited 1 time in total.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: A *much* better way of doing Singleton's (IMO)

Post by nullsquared »

JohnJ wrote:
Because it takes singletons and makes them even more implicit than they already are.
Did you read the last paragraph of my first post? I already proved this argument is wrong. I'll summarize: My technique is just as explicitly obvious that it's a singleton as Ogre's implementation, unless your definition of "explicit" includes a requirement for 15 characters of explicitness every time it's used. But by that logic though, you could claim that "object->member" notation is bad because it's "less explicit" than "(*object).member".
I dont use ClassNamesLikeThis. myClassesLookLikeThis. doingSomethlingLikeThis_singleton or doing somethingLikeThisSingleton or something of the sort is worthless, and no better than simply using getSingleton() in the first place. If MyClass is notation for a class, first thing I see is calling operator->() as a static function, which is impossible, and only confusing. object->member is not any less explicit than (*object).member, they are the exact same thing.
Don't use singletons, they're worthless and error-prone.
I didn't think I would have to state the obvious here: This isn't a debate about where and why singletons should or shouldn't be used. It's about what's the best implementation, in the event a singleton is necessary for whatever reason there may be.

I agree that singletons should not be used unless absolutely necessary. But, if you want to debate where and why singletons should or shouldn't be used, please start a new thread and I'll be happy to elaborate my views on the matter :).
It was already done. There are no arguments for using singletons, they can all be countered, and in the end, singletons are not to be used, period.
User avatar
JohnJ
OGRE Expert User
OGRE Expert User
Posts: 975
Joined: Thu Aug 04, 2005 4:14 am
Location: Santa Clara, California
x 4

Re: A *much* better way of doing Singleton's (IMO)

Post by JohnJ »

I dont use ClassNamesLikeThis. myClassesLookLikeThis. doingSomethlingLikeThis_singleton or doing somethingLikeThisSingleton or something of the sort is worthless, and no better than simply using getSingleton() in the first place.
I used to use a style like that, and I'm certainly glad I don't any more. There are various reasons for why this is, but I won't get into that now. But whatever your naming convention is, you surely can find a suitable method to make use of this technique in a clean, logical way - if you want to, that is. But I suspect you don't care about singletons at all from the last sentence of your post.
If MyClass is notation for a class, first thing I see is calling operator->() as a static function, which is impossible, and only confusing.
I think it's quite intuitive to call "MyClass->function();" for a singleton. The only confusing part would be when you look at this syntax for the first time ever and notice the syntax doesn't make sense in basic C++. This is a good thing, because:

- It separates the new behavior I've defined for singletons from other operations which makes it an explicit feature which is automatically distinguishable.
- Singletons are the conceptual equivalent of namespaces containing functions and variables, but implemented as a class for easier development and refactoring. With that in mind, I think it makes perfect sense that it would be accessed like "MyClass->function();" - it's not a completely static class (explaining the "->"), yet there's only one instance ever (explaining the use of the class name to access it).

Additionally, if a programmer who first encounters this notation is confused, in Visual Studio at least all they need to do is hover the mouse over the "MyClass" part, and they'll instantly see that it's a "SmartSingleton<Singleton::MyClass>" object - and everything will make sense.
object->member is not any less explicit than (*object).member, they are the exact same thing.
"MyClass->function();" is not any less explicit than "MyClass::getSingleton().function();", they are the exact same thing.
It was already done. There are no arguments for using singletons, they can all be countered, and in the end, singletons are not to be used, period.
To say the least, there are some logical flaws with that statement. However just as that comment is off-topic in this thread, so would be my response. Like I said, please make another thread for this if you want to discuss it.

Basically I'm be interested to hear people's opinions on whether they like this technique or not, and why. I'm willing to share my code but I probably won't publicly release it unless enough people actually want it. I don't mean to encourage people to overuse singletons, but just to provide an improved (I hope) implementation for where it is used.
Last edited by JohnJ on Sat Jul 04, 2009 8:55 am, edited 1 time in total.
User avatar
_tommo_
Gnoll
Posts: 677
Joined: Tue Sep 19, 2006 6:09 pm
x 5
Contact:

Re: A much better way of doing Singleton's

Post by _tommo_ »

I do find that singletons are better to not be used, but sometimes they do their dirty job :)
So i'm quite interested in JohnJ implementation... how did you made it?

Static overloaded operator-> ?
If yes it is cool but indeed a bit confusing for newbies :)
OverMindGames Blog
IndieVault.it: Il nuovo portale italiano su Game Dev & Indie Games
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: A much better way of doing Singleton's

Post by jacmoe »

If people are so against singletons, why not just submit a patch against the Ogre source code?
Just see how easy that is going to be. :wink:
Singletons solves a lot of problems with ownership and scope, which is why it's difficult to un-singleton-ify Ogre.
But: surprise me.

I'd be interested in hearing more about your better singleton, JohnJ. :)
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: A *much* better way of doing Singleton's (IMO)

Post by nullsquared »

JohnJ wrote: Additionally, if a programmer who first encounters this notation is confused, in Visual Studio at least all they need to do is hover the mouse over the "MyClass" part, and they'll instantly see that it's a "SmartSingleton<Singleton::MyClass>" object - and everything will make sense.
What happened to self-documenting code? Now I must mouse-over everything to know what the hell it's doing or what it is?
object->member is not any less explicit than (*object).member, they are the exact same thing.
"MyClass->function();" is not any less explicit than "MyClass::getSingleton().function();", they are the exact same thing.
Um. Yes it is.

foo->bar() is C++ syntactic sugar for (*foo).bar

MyClass->function() is not syntactic sugar for anything. It looks like a static operator->(), but you can't have a static operator->(). So then unless you explicitly make it look like a singleton every time (which is what getSingleton() does), no one who is reading your code will know what it is doing. That's Bad (tm).
Basically I'm be interested to hear people's opinions on whether they like this technique or not, and why. I'm willing to share my code but I probably won't publicly release it unless enough people actually want it. I don't mean to encourage people to overuse singletons, but just to provide an improved (I hope) implementation for where it is used.
It's an interesting idea, but not a good one. If it's possible to say singletons had any good in them at all, it just got destroyed ;) But then again, it's impossible to say singletons had any good in them, so the statement is null and void.
jacmoe wrote:If people are so against singletons, why not just submit a patch against the Ogre source code?
Just see how easy that is going to be. :wink:
There we have yet another pitfall of singletons. Start to use them and you'll be in refactoring hell when you decide to get rid of them.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: A *much* better way of doing Singleton's (IMO)

Post by jacmoe »

nullsquared wrote:There we have yet another pitfall of singletons. Start to use them and you'll be in refactoring hell when you decide to get rid of them.
I can't avoid agreeing with you there. :wink:
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
JohnJ
OGRE Expert User
OGRE Expert User
Posts: 975
Joined: Thu Aug 04, 2005 4:14 am
Location: Santa Clara, California
x 4

Re: A *much* better way of doing Singleton's (IMO)

Post by JohnJ »

Jacmoe: The implementation is actually extremely simple, almost disappointing if you were expecting an elaborate and confusing implementation :). I'll probably post the code soon.
nullsquared wrote:
JohnJ wrote: Additionally, if a programmer who first encounters this notation is confused, in Visual Studio at least all they need to do is hover the mouse over the "MyClass" part, and they'll instantly see that it's a "SmartSingleton<Singleton::MyClass>" object - and everything will make sense.
What happened to self-documenting code? Now I must mouse-over everything to know what the hell it's doing or what it is?
Somehow I knew you would take this out of context. Notice the "additionally" and "if" in that sentence? Also notice an absence of the words "must" and "everything".

You've clearly made up your mind, so all I'll say is this: my method needs no documentation at all to use - it just makes sense.
"MyClass->function();" is not any less explicit than "MyClass::getSingleton().function();", they are the exact same thing.
Um. Yes it is.

foo->bar() is C++ syntactic sugar for (*foo).bar

MyClass->function() is not syntactic sugar for anything. It looks like a static operator->(), but you can't have a static operator->().
I disagree, MyClass->function() is just as much syntactic sugar, the only difference is it's not integrated into the language by default. Consider it an extension.
So then unless you explicitly make it look like a singleton every time (which is what getSingleton() does), no one who is reading your code will know what it is doing. That's Bad (tm).
1. It does explicitly look like a singleton, just in a different way than you're accustomed to. I already explained this.
2. You're simply wrong to say "no one who is reading your code will know what it is doing."
There we have yet another pitfall of singletons. Start to use them and you'll be in refactoring hell when you decide to get rid of them.
There are a million pitfalls to singletons, but this thread isn't about whether singletons are to be used or not.
It's an interesting idea, but not a good one. If it's possible to say singletons had any good in them at all, it just got destroyed ;) But then again, it's impossible to say singletons had any good in them, so the statement is null and void.
Again, this isn't a thread about whether singletons are to be used or not. Your argument that singletons are 100% undeniably useless must feel threatened if you have to repeat it over and over here, where I've already asked you to make another thread for these assertions / arguments.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: A *much* better way of doing Singleton's (IMO)

Post by nullsquared »

JohnJ wrote: 2. You're simply wrong to say "no one who is reading your code will know what it is doing."
Well, clearly, I have no clue what your code is doing, because it doesn't look like a singleton to me. I'm sure others will have the same issue. Just because it looks like a singleton to you doesn't mean anything (after all, you're the one who wrote the idea). Readers of your code will be confused.

Syntactic sugar that is part of the language is known to everyone. Syntactic sugar that is an "extension" is not known to everyone.
There we have yet another pitfall of singletons. Start to use them and you'll be in refactoring hell when you decide to get rid of them.
There are a million pitfalls to singletons, but this thread isn't about whether singletons are to be used or not.
I was replying to jacmoe.
User avatar
JohnJ
OGRE Expert User
OGRE Expert User
Posts: 975
Joined: Thu Aug 04, 2005 4:14 am
Location: Santa Clara, California
x 4

Re: A much better way of doing Singleton's

Post by JohnJ »

Syntactic sugar that is part of the language is known to everyone. Syntactic sugar that is an "extension" is not known to everyone.
Better not use STL then; it's not known to everyone else. Oh, and you better not access your std::vectors by "myVector[index]" - after all, it's a syntax error to access a class with subscript operators, right?
Well, clearly, I have no clue what your code is doing, because it doesn't look like a singleton to me. I'm sure others will have the same issue. Just because it looks like a singleton to you doesn't mean anything (after all, you're the one who wrote the idea). Readers of your code will be confused.
Tell me then, how could you possibly interpret this notation as anything but either:
1. A syntax error (which it is clearly not)
2. A singleton.
Last edited by JohnJ on Sat Jul 04, 2009 3:49 pm, edited 2 times in total.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: A much better way of doing Singleton's

Post by nullsquared »

JohnJ wrote:
Syntactic sugar that is part of the language is known to everyone. Syntactic sugar that is an "extension" is not known to everyone.
Better not use Ogre then; it's not known to everyone else.
What? :|

Ogre is a library. It has nothing to do with syntactic sugar.
JohnJ wrote:
Syntactic sugar that is part of the language is known to everyone. Syntactic sugar that is an "extension" is not known to everyone.
Better not use STL then; it's not known to everyone else. Oh, and you better not access your std::vectors by "myVector[index]" - after all, it doesn't make sense to access a class with subscript operators, right?
Again, what?

I don't think you get the point. myVector[index] makes perfect sense. I see "access myVector (which is an instance, not a type) at index via the overloaded operator[]". That makes perfect sense.

(BTW, the STL/SC++L is actually a part of the language, and therefore it must be known to everyone ;)
Well, clearly, I have no clue what your code is doing, because it doesn't look like a singleton to me. I'm sure others will have the same issue. Just because it looks like a singleton to you doesn't mean anything (after all, you're the one who wrote the idea). Readers of your code will be confused.
Tell me then, how could you possibly interpret this notation as anything but either:
1. A syntax error (which it is clearly not)
2. A singleton.
Syntax error. Foo->bar() looks like a static operator->() (as I've said mean times).
Last edited by nullsquared on Sat Jul 04, 2009 3:50 pm, edited 1 time in total.
User avatar
JohnJ
OGRE Expert User
OGRE Expert User
Posts: 975
Joined: Thu Aug 04, 2005 4:14 am
Location: Santa Clara, California
x 4

Re: A much better way of doing Singleton's

Post by JohnJ »

What?

Ogre is a library. It has nothing to do with syntactic sugar.
You're fast :). I edited that to STL because it makes more sense in this case.
Better not use STL then; it's not known to everyone else. Oh, and you better not access your std::vectors by "myVector[index]" - after all, it's a syntax error to access a class with subscript operators, right?
Syntax error. Foo->bar() looks like a static operator->() (as I've said mean times).
Lol, read the question again (keywords "anything but either").
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: A much better way of doing Singleton's

Post by nullsquared »

JohnJ wrote:
What?

Ogre is a library. It has nothing to do with syntactic sugar.
You're fast :). I edited that to STL because it makes more sense in this case.
Better not use STL then; it's not known to everyone else. Oh, and you better not access your std::vectors by "myVector[index]" - after all, it's a syntax error to access a class with subscript operators, right?
I also edited.
Syntax error. Foo->bar() looks like a static operator->() (as I've said mean times).
Lol, read the question again (keywords "anything but either[/i]").

Right. And I said it isn't anything else, but a syntax error. Only way to know "it is obviously not" (not really so obvious) is to compile or mouse-over. Which leads us back to the issue of self-documenting code.
User avatar
JohnJ
OGRE Expert User
OGRE Expert User
Posts: 975
Joined: Thu Aug 04, 2005 4:14 am
Location: Santa Clara, California
x 4

Re: A much better way of doing Singleton's

Post by JohnJ »

(BTW, the STL/SC++L is actually a part of the language, and therefore it must be known to everyone ;)
It's a standard, yes, but it's still a library. Maybe a better example for you would be just anything with any sort of operator overloading.
Again, what?

I don't think you get the point. myVector[index] makes perfect sense. I see "access myVector (which is an instance, not a type) at index via the overloaded operator[]". That makes perfect sense.
I don't think you get the point. MyClass->doStuff() makes perfect sense. I see "run the doStuff() method of MyClass via the overloaded operator->". That makes perfect sense.

Maybe you should explain why you think "MyClass->function();" doesn't make perfect sense in exactly the same way as shown above. Both would normally be a syntax error if it wasn't for operator overloading. Both assumes the reader understands something about the nature of the class. In the case of "myVector[index]", a competent programmer will assume by this notation that it's some kind of container - it's obvious. In the case of "MyClass->function();" a competent programmer will assume by this notation that it's some kind of singleton - it's obvious.
Only way to know "it is obviously not" (not really so obvious) is to compile or mouse-over. Which leads us back to the issue of self-documenting code.
I guess I'll have to go back to the vector example. Lets say you had this code within a class function:

Code: Select all

myVector.add(value);
for (int i = 0; i < myVector.count(); ++i) {
    int val = myVector[i];
    //...
}
How would you know that the "[]" notation being used on an obviously non-array object won't cause a syntax error without compiling, or looking up the declaration of "myVector"?
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: A much better way of doing Singleton's

Post by jacmoe »

JohnJ wrote:I don't think you get the point.
I don't think the point is to get the point. Not with Nullsquared.. :wink:
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: A much better way of doing Singleton's

Post by nullsquared »

JohnJ wrote: Maybe you should explain why you think "MyClass->function();" doesn't make perfect sense in exactly the same way as shown above.
"What is MyClass?"

Name notation leads me to believe it's a class. But by your theory, it's actually an instance. Then what does your method have over this:

Code: Select all

thereShouldOnlyBeOne instance;

instance.doStuff();
(for example, the way std::cout and std::cerr, etc. are done)
How would you know that the "[]" notation being used on an obviously non-array object won't cause a syntax error without compiling, or looking up the declaration of "myVector"?
myVector looks like a clear instance of something. Using [] on an instance of something means the operator must be overloaded for this type. Your's looks like calling an overloaded operator on the class type itself, which does not make sense - but it makes perfect sense calling it on an instance.
Last edited by nullsquared on Sat Jul 04, 2009 6:08 pm, edited 1 time in total.
User avatar
nikki
Old One
Posts: 2730
Joined: Sat Sep 17, 2005 10:08 am
Location: San Francisco
x 13
Contact:

Re: A much better way of doing Singleton's

Post by nikki »

Actually, I'm more for the 'global access' than the 'one instance' idea of singletons.

I don't know, I just like having easy access to stuff. Of course this is might be bad in a library, but in an end-user application I think it's fine.
User avatar
JohnJ
OGRE Expert User
OGRE Expert User
Posts: 975
Joined: Thu Aug 04, 2005 4:14 am
Location: Santa Clara, California
x 4

Re: A much better way of doing Singleton's

Post by JohnJ »

nikki: singleton = global access. In concept, a singleton is nothing but a group of global variables and functions, wrapped using a class to make it easier to read and maintain.

However I actually agree with nullsquared that global access like this should be avoided if possible. He's absolutely right that use of singletons can be a very bad design, but I disagree that this is true in all cases 100% of the time. My approach to programming is simple: use features with care and common sense. So I acknowledge the fact that in very rare cases singletons (aka global access to variables or functions) is sometimes necessary, and even logical.

Anyway, here's my code:

EDIT: Moved to first thread post.

As you can see I implement a singleton as what it truly is: a global variable (managed in a way that makes it more suitable to singletons). If anyone, like nullsquared, objects to naming this global variable to look like a class, you're not required to. For example this wouldn't be too bad:

Code: Select all

gMyClass = new Singleton::MyClass();
gMyClass->doStuff();
But I still prefer the method demonstrated in my first post here, IMO it's cleaner, simpler, and makes more sense in the context of a singleton.
Last edited by JohnJ on Tue Jul 07, 2009 11:18 pm, edited 3 times in total.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: A *much* better way of doing Singleton's (IMO)

Post by jacmoe »

JohnJ wrote:Jacmoe: The implementation is actually extremely simple, almost disappointing if you were expecting an elaborate and confusing implementation :).
I am a big fan of simplicity over cleverness! :)
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
stoneCold
OGRE Expert User
OGRE Expert User
Posts: 867
Joined: Fri Oct 01, 2004 9:13 pm
Location: Carinthia, Austria
x 1

Re: A much better way of doing Singleton's

Post by stoneCold »

Thx for sharing your snippet JohnJ.

Concerning Singletons... I know they have many pitfalls, and just like JohnJ I try to use them ONLY when common sense tells me it would be useful/fitting.
Anyway, I've seen way too many threads complaining about Singletons and telling not to use them at any time.
Maybe we could be able to give an overview of the alternatives to singletons this time, instead of just starting a flame war about whether singletons are legitimate or not.
This way, maybe something constructive can come out of this discussion (additionally to JohnJ's snippet, thx again for sharing).

my 0.02$
User avatar
_tommo_
Gnoll
Posts: 677
Joined: Tue Sep 19, 2006 6:09 pm
x 5
Contact:

Re: A much better way of doing Singleton's

Post by _tommo_ »

Really clever, i have to use it somewhere :D
For the fans of explicit code, it could even be better because

Code: Select all

LogSingleton = new Log(..)
LogSingleton->log("hello world");
Is actually a thousand times better than the current ogre mess, for example :wink:
OverMindGames Blog
IndieVault.it: Il nuovo portale italiano su Game Dev & Indie Games
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: A much better way of doing Singleton's

Post by jacmoe »

Code: Select all

LogSingleton = Ogre::LogManager::getSingletonPtr();
LogSingleton->log("hello world");
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
Post Reply