Singleton Discussion

A place for Ogre users to discuss non-Ogre subjects with friends from the community.
mirlix
Goblin
Posts: 225
Joined: Mon May 01, 2006 12:03 am
Location: Germany
x 5

Re: Singleton Discussion

Post by mirlix »

nullsquared wrote:
mirlix wrote:Now you cant get an error because two instances exist, but you cant get an error when you try to create a second instance
What? There is only one instance. Whatever needs to access that instance will receive a reference to it. There is no room for error, because the instance will be only created in one spot.
What I mean is that your program will terminate when the following happens

Code: Select all

int main()
{
    thereShouldOnlyBeOne instance;
    thereShouldOnlyBeOne instance2;//Here the program dies

    foo(instance);
}
In this case the error is easy to find, but it could be in totally different totally unrelated code files, then it gets tricky. And even worse, like stated before, you can have correct code which works without an error. Now comes a second programmer along who creates some code which is run before your code and there he create an instance of this class. Now your code fails without an error in your code. In my opinion it would be better to use the following technique. Because your approach doesnt prevent the error of two instance existing, it only shifts the point when the error occurs.

Code: Select all

int main()
{
    thereShouldOnlyBeOne* instance =     thereShouldOnlyBeOne::getSingleton():
    thereShouldOnlyBeOne* instance2 = thereShouldOnlyBeOne::getSingleton():;//Here the program doesnt die but instance2 == instance

    foo(instance);
}
JohnJ wrote: Apparently we have an inconsistency of naming here. To me, "singleton" = "global class". To you, "singleton" = "debug assertion" (basically). I think the latter is a bad idea because a debug assertion does nothing to resolve the root problem, just defers it to another area of code.
Not excatly. My target with the getInstance() method would be that no error occurs, you simply get always the same instance when calling the method. This would solve the problem of two instances existing at the same time. I cant disagree that a singleton is always a global class, but this shouldnt be the reason for making a singleton, sometimes you have to but quite often there is another way.
User avatar
syedhs
Silver Sponsor
Silver Sponsor
Posts: 2703
Joined: Mon Aug 29, 2005 3:24 pm
Location: Kuala Lumpur, Malaysia
x 51

Re: Singleton Discussion

Post by syedhs »

steven wrote:I don't see why I would need more than one EngineManger, GraphicsManager, LogManager, NetworkManager, InputManager and some others.

So why should I bother to pass references or pointers everywhere and not simply access them via singleton?
It makes lots of constructors and methods simpler.
Yes I agree with you - it all boils down to practicality. All those 'religious' issues like 'never use singleton' and followed by technical explanation which isn't really understood should not be accepted. I really think the conundrum of having singleton (or not) will only arise once your project becomes large enough and in most cases, can be managed if you know what you are doing.
A willow deeply scarred, somebody's broken heart
And a washed-out dream
They follow the pattern of the wind, ya' see
Cause they got no place to be
That's why I'm starting with me
CABAListic
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 2903
Joined: Thu Jan 18, 2007 2:48 pm
x 58
Contact:

Re: Singleton Discussion

Post by CABAListic »

nullsquared wrote:I smell design issues. Not only is it a global, but it is a global with a non-trivial constructor that needs to log something?
So, next thing you're going to tell me that you have never, ever inserted a log statement inside a constructor, not even temporarily for debug purposes? Heh, I swear you must be the god of infallible software design.
In any case, the point is that a Meyers singleton is in fact nothing else but a global variable minus the mentioned order of creation problem and an added implicit (no runtime errors) ensurance that you are only ever using the single instance of it. So tell me again, what makes your global variable better for the log system?
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: Singleton Discussion

Post by nullsquared »

CABAListic wrote:
nullsquared wrote:I smell design issues. Not only is it a global, but it is a global with a non-trivial constructor that needs to log something?
So, next thing you're going to tell me that you have never, ever inserted a log statement inside a constructor, not even temporarily for debug purposes?
In a constructor, yes. Not in a global variable's constructor.
So tell me again, what makes your global variable better for the log system?
I can create as many of it as I want. I can even create derived types (such as, you know, std::ofstream ;))
JohnJ wrote:
And if you really need your own class for it:

Code: Select all

class logger { ... };

// .hpp
extern logger log;

// .cpp
logger log;

// elsewhere
log << "logging stuff, yay!";
That's almost exactly how my singleton implementation works, but mine is a little more flexible with construction. After seeing this, I'm starting to think the main disagreement between you/me on this is simply due to an inconsistency of the definition of "singleton".
Perhaps. What you're talking about is not a singleton. That is simply a global variable. Nothing to do with singletons.
Input is cause, stuff happening is effect. Processing, applying, or halting program execution with a prompt are all effect. Input does not care about effect, as it is the cause. The only thing it does (and, well, the only thing it can do) is capture input.
My point was "input" is a vague verb, and is therefore ambiguous in many cases. You're little code example proves this very nicely:

Code: Select all

input::input input(...);
input();
Not exactly self documenting.
Alright, so my input class is named a bit ambiguously because its namespace is also named input. But you can't just mash those parts together like that - they have a context (one which I cut out so I can only show you the input part - imagine there's more to it in the /* ... */ blocks).
In the case of the code you posted, it looks like it's more likely to be problematic with chains of backward dereferences, like "body.world.root.input.keyboard.isKeyDown()" (just an example). Rather than "Keyboard->isKeyDown()". I'll assume for now that I don't need to explain why the former is horrible design, but let me know if you need me to explain it. Now I'm not saying you have a problem like this, but that it's my best guess as to where a singleton could help, considering I don't know much about the rest of your code.
No. Once again, I smell design issues.

body is a physics body class. The world is the physics world class (they'e both in the phys namespace). The body might need to know about it's world, for example, to be created properly (for example, when I use Newton, to create a body, you need to pass the World it is created within). It does NOT need to know anything about keyboards, input, roots, etc. Give me a better example for your "reference chaining" and I'll show you how I don't have that problem.
You've even posted some yourself. "std::clog", for example, is just as much a singleton as "Ogre::LogManager::getSingleton()" for all practical purposes.
No. I can create as many ostreams (or types derived from ostreams) as I want. std::clog is simply a global.
To be perfectly honest I don't like arguing for singletons, because I don't like them in most cases anyway. I already gave you the example of the keyboard class. I could type up a long code example demonstrating exactly why it's advantageous, but at this point I've wasted enough time already on this thread.
Well then instead of wasting your time on telling me about the "keyboard example," you should've simply shown me the "keyboard example." Besides my ambiguous naming, my method is perfectly fine. Look at it this way if you really can't get past the simple naming:

Code: Select all

engine::input::inputSystem input(root->hwnd());

while (...)
{
    ...
    input();
    ...
}
No singletons. No globals. No need.
steven wrote:I don't see why I would need more than one EngineManger, GraphicsManager, LogManager, NetworkManager, InputManager and some others.

So why should I bother to pass references or pointers everywhere and not simply access them via singleton?
It makes lots of constructors and methods simpler.
I'll assume that your GraphicsManager is the equivalent of my renderer (handles the graphics and actual rendering).

In my game, you'll be able to have in-game computers. These in-game computers can render scenes from the game (like a camera). In my non-singleton case, I can simply create a second renderer specifically for the in-game computer, and done:

Code: Select all

computer::computer()
{
    // create our own scene manager so that the scene doesn't conflict with the game's scene
    _sceneMgr = ...;

    _renderer.reset(new forwardRenderer(_screen.viewport(), _sceneMgr));
}

void computer::tick(...)
{
    _renderer.render(); // render to our screen
}
Since my entity manager (aka my game::world) is also not a singleton, my in-game computer can start spawning its own entities in its own little world, etc.
mirlix wrote: Not excatly. My target with the getInstance() method would be that no error occurs, you simply get always the same instance when calling the method. This would solve the problem of two instances existing at the same time. I cant disagree that a singleton is always a global class, but this shouldnt be the reason for making a singleton, sometimes you have to but quite often there is another way.
I see what you're saying. What about, perhaps:

Code: Select all

// instead of thereShouldOnlyBeOne, I'll call it foo this time to be easy
class foo
{
    private:
        foo();
        foo(const foo&);
        foo &operator=(const foo&);

        friend foo &createFooImpl(const char *file, const char *func, unsigned line);
};

foo &createFooImpl(const char *file, const char *func, unsigned line)
{
    static bool alreadyExists = false;
    if (alreadyExists)
    {
        std::cerr << "created second foo in " << file << " in " << func " on line " << line;
        assert(false && "create only one foo");
    }
    static foo theFoo;
    return theFoo;
}

#define createFoo() createFooImpl(__FILE__, __FUNCTION__, __LINE__)

void bar(foo &ourFoo)
{
    foo theFoo; // compiler error
    foo &theFoo2 = createFoo(); // "created second foo in main.cpp in void bar(foo &ourFoo) on line 123" <assert>
}

int main()
{
    foo &ourFoo = createFoo();

    bar(ourFoo);
}
This way you find the issue, instead of simply avoiding it.
CABAListic
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 2903
Joined: Thu Jan 18, 2007 2:48 pm
x 58
Contact:

Re: Singleton Discussion

Post by CABAListic »

nullsquared wrote: I can create as many of it as I want. I can even create derived types (such as, you know, std::ofstream ;))
But that's the point: You are not supposed to. You keep comparing a log system to std::clog, but seriously, any sophisticated log system is more than a primitive output (and clog is nothing more). Most log systems I know have timestamps, log levels, whatever. They probably also need to deal with serialising access in multi-threaded applications.
Nothing of which clog provides.
If you create two instances of your log system, both of which happen to output to the console (or to the same file, for that matter), you bypass the thread serialisation. And this is an error. The singleton prevents the error.
(Technically speaking, the console output part of your log system is the one that needs to exist only once. A higher-level log target which routes log messages to one or several outputs could be instantiated multiple times if you desire. But that's irrelevant for the argument).
mirlix
Goblin
Posts: 225
Joined: Mon May 01, 2006 12:03 am
Location: Germany
x 5

Re: Singleton Discussion

Post by mirlix »

nullsquared wrote:This way you find the issue, instead of simply avoiding it.
I dont want to find the issue, I want to prevent it from happing. The point of my singleton idea is to be sure there is only one instance and everybody who needs to use the class gets the same instance. Nothing more and nothing less. Simply printing an error message doenst help making a program more robust, prevent the misuse does :)
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: Singleton Discussion

Post by nullsquared »

CABAListic wrote:Nothing of which clog provides.
Really?

http://www.gamedev.net/reference/snippe ... ogSnippet/
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: Singleton Discussion

Post by JohnJ »

No. I can create as many ostreams (or types derived from ostreams) as I want. std::clog is simply a global.
Tell me, how many std::clogs are there at once? Two? Five? Oh wait... there's only ever one. "I smell" a Singleton :)
No. Once again, I smell design issues.
That was my whole point.
body is a physics body class. The world is the physics world class (they'e both in the phys namespace). The body might need to know about it's world, for example, to be created properly (for example, when I use Newton, to create a body, you need to pass the World it is created within). It does NOT need to know anything about keyboards, input, roots, etc. Give me a better example for your "reference chaining" and I'll show you how I don't have that problem.
I didn't say you had this problem, I said this is one of the types of common problems singletons can provide a cleaner solution to in rare cases. I can't provide you a better example, you're essentially asking me to find a problem with your code without even seeing your code.

Code: Select all

engine::input::inputSystem input(root->hwnd());

while (...)
{
    ...
    input();
    ...
}
This is just as bad. Again, what is input();? What scope is this? I need to know how input() or whatever accesses the input system object before I can give you an example of how a global/singleton would improve this.
CABAListic
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 2903
Joined: Thu Jan 18, 2007 2:48 pm
x 58
Contact:

Re: Singleton Discussion

Post by CABAListic »

nullsquared wrote:
CABAListic wrote:Nothing of which clog provides.
Really?

http://www.gamedev.net/reference/snippe ... ogSnippet/
Yes, really. What they do there is nothing other than implement those missing features, because clog does not provide any of them. That they redirect clog to their implementation instead of building an implementation on top of clog or cout is a design choice and irrelevant to the argument. Besides, it needs explicit setup at the start of your program, whereas my log system does not. In that regard, my approach is friendlier for reuse ;)
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: Singleton Discussion

Post by nullsquared »

JohnJ wrote:
No. I can create as many ostreams (or types derived from ostreams) as I want. std::clog is simply a global.
Tell me, how many std::clogs are there at once? Two? Five? Oh wait... there's only ever one. "I smell" a Singleton :)
A singleton is a class type of which there can only exist one of. std::clog is a global, not a singleton.
body is a physics body class. The world is the physics world class (they'e both in the phys namespace). The body might need to know about it's world, for example, to be created properly (for example, when I use Newton, to create a body, you need to pass the World it is created within). It does NOT need to know anything about keyboards, input, roots, etc. Give me a better example for your "reference chaining" and I'll show you how I don't have that problem.
I didn't say you had this problem, I said this is one of the types of common problems singletons can provide a cleaner solution to in rare cases.
Nope, this is a common problem that should have some refactoring done. Simply falling back to a singleton/globals is avoiding the issue, not fixing it.

Code: Select all

engine::input::inputSystem input(root->hwnd());

while (...)
{
    ...
    input();
    ...
}
This is just as bad. Again, what is input();? What scope is this? I need to know how input() or whatever accesses the input system object before I can give you an example of how a global/singleton would improve this.
Like I said, it doesn't matter. input() does ... well, input. That's all you need to know at the current level of code (program flow goes like this: input -> logic -> render, repeat; this is exactly what I've done at this level of code). What it does under the hood is an implementation detail which is encapsulated. This just further proves that a singleton/global would be useless here.

Also, did you completely miss my example?
nullsquared wrote: Tell me, what happens when you want to simulate the input (not perfect example, but an example none-the-less)? In my case, simple.

Code: Select all

//input::input input(...);
// use simulated input, instead
input::simulatedInput input(...); // tada.  everything Just Works
Last edited by nullsquared on Sun Jul 05, 2009 3:48 pm, 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: Singleton Discussion

Post by nullsquared »

CABAListic wrote:
nullsquared wrote:
CABAListic wrote:Nothing of which clog provides.
Really?

http://www.gamedev.net/reference/snippe ... ogSnippet/
Yes, really. What they do there is nothing other than implement those missing features, because clog does not provide any of them. That they redirect clog to their implementation instead of building an implementation on top of clog or cout is a design choice and irrelevant to the argument. Besides, it needs explicit setup at the start of your program, whereas my log system does not. In that regard, my approach is friendlier for reuse ;)
Um. OK, but I still fail to see why this warrants a singleton.
CABAListic
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 2903
Joined: Thu Jan 18, 2007 2:48 pm
x 58
Contact:

Re: Singleton Discussion

Post by CABAListic »

*sigh* As I said, thread synchronisation only works if there's only ever one instance of whichever class does the synchronisation. Which is exactly what a singleton ensures.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: Singleton Discussion

Post by nullsquared »

CABAListic wrote:*sigh* As I said, thread synchronisation only works if there's only ever one instance of whichever class does the synchronisation. Which is exactly what a singleton ensures.
You can synchronise it that way using a simple global, too (for example, my link does synchronisation via std::clog). Like I said, it does not warrant a singleton.
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: Singleton Discussion

Post by JohnJ »

In my game, you'll be able to have in-game computers. These in-game computers can render scenes from the game (like a camera). In my non-singleton case, I can simply create a second renderer specifically for the in-game computer, and done
You need to create an entirely new render system object to render multiple camera views? "I smell design issues."
That is simply a global variable. Nothing to do with singletons.
How many global variables called "clog" do you have?

Here is a code example that might help nullsquared understand the use of singletons and their practical equivalence to globals, or for anyone else who can't understand it in abstract and needs a practical example:

Without singleton/global:

Code: Select all

class PhysicsBody
{
    World *world;
    ...
    void someFunction()
    {
        ...
        //Error!
        world->getRenderer()->getRoot()->getLogger() << "Error message!";
    }
    ...
}
With singleton/global:

Code: Select all

class PhysicsBody
{
    World *world;
    ...
    void someFunction()
    {
        ...
        //Error!
        Log.getSingleton() << "Error message!";
        //OR
        std::clog << "Error message!";
    }
    ...
}
If you don't see the practical equivalence of a singleton to a global variable here, then you either "just doesn't get it", or are arguing for the sake of arguing.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: Singleton Discussion

Post by nullsquared »

JohnJ wrote:
In my game, you'll be able to have in-game computers. These in-game computers can render scenes from the game (like a camera). In my non-singleton case, I can simply create a second renderer specifically for the in-game computer, and done
You need to create an entirely new render system object to render multiple camera views? "I smell design issues."
Render system? gfx::renderer has nothing to do with Ogre::RenderSystem. It is what its name implies - a renderer. It abstracts away rendering (for example, I have both a forwardRenderer and a deferredRenderer - the main game can use one, but an in-game computer can use the other).
That is simply a global variable. Nothing to do with singletons.
How many global variables called "clog" do you have?
Image
Wikipedia wrote: In software engineering, the singleton pattern is a design pattern that is used to restrict instantiation of a class to one object.
Why are you so stubborn to acknowledge that std::clog is NOT a singleton, but a GLOBAL? And you're calling me the stubborn teenager.
Here is a code example that might help nullsquared understand the use of singletons and their practical equivalence to globals, or for anyone else who can't understand it in abstract and needs a practical example:

Without singleton/global:

Code: Select all

class PhysicsBody
{
    World *world;
    ...
    void someFunction()
    {
        ...
        //Error!
        world->getRenderer()->getRoot()->getLogger() << "Error message!";
    }
    ...
}
No. Without global:

Code: Select all

class PhysicsBody
{
    World &world;
    Logger &log;

    // disregarding the fact that you made this all under private:
    PhysicsBody(World &world, Logger &log): world(world), log(log) {}

    ...
    void someFunction()
    {
        ...
        //Error!
        log << "Error message!";
    }
    ...
}
But, of course, that's more of an example for other stuff, as a logger would be a global. Not a singleton, but a global. (BTW, I have no clue why the physics world (or really, any of the worlds) would have a pointer/reference to the renderer)
CABAListic
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 2903
Joined: Thu Jan 18, 2007 2:48 pm
x 58
Contact:

Re: Singleton Discussion

Post by CABAListic »

nullsquared wrote: You can synchronise it that way using a simple global, too (for example, my link does synchronisation via std::clog). Like I said, it does not warrant a singleton.
You just don't get it, do you? The point is that there can only be one single instance of your global, because if you begin using more than one instance of your synchronisation object, then you can no longer correctly do the synchronisation.
In summary: You need a global to do the synchronisation, and you need exactly one instance. And that means it's a Singleton. As simple as that. If you use a global for the purpose, then it is still a Singleton, but your code does not enforce the single instance rule, i. e. you must ensure the single instance manually. The Singleton pattern prevents a possible programmer error, and therefore it's superiour to your global.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: Singleton Discussion

Post by nullsquared »

CABAListic wrote:
nullsquared wrote: You can synchronise it that way using a simple global, too (for example, my link does synchronisation via std::clog). Like I said, it does not warrant a singleton.
You just don't get it, do you? The point is that there can only be one single instance of your global, because if you begin using more than one instance of your synchronisation object, then you can no longer correctly do the synchronisation.
What, are you going to "accidentally" make a second global? :roll:
In summary: You need a global to do the synchronisation, and you need exactly one instance. And that means it's a Singleton. As simple as that. If you use a global for the purpose, then it is still a Singleton, but your code does not enforce the single instance rule, i. e. you must ensure the single instance manually. The Singleton pattern prevents a possible programmer error, and therefore it's superiour to your global.
See this:
nullsquared wrote: Image
Wikipedia wrote: In software engineering, the singleton pattern is a design pattern that is used to restrict instantiation of a class to one object.
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: Singleton Discussion

Post by JohnJ »

Render system? gfx::renderer has nothing to do with Ogre::RenderSystem. It is what its name implies - a renderer. It abstracts away rendering (for example, I have both a forwardRenderer and a deferredRenderer - the main game can use one, but an in-game computer can use the other).
I knew that. Having both a forwardRenderer and deferredRenderer makes even less sense to me. How do you handle transparency? In my engine it's automatic because it's all managed by one Renderer (not a singleton btw).
And you're calling me the stubborn teenager.
I didn't call you a stubborn teenager, I said your post shows a common mistake made be teenagers, regardless of whether you're a teenager or not. Even if you are a teenager, it doesn't mean you can't at least try to act professionally. That's all I meant. BTW, I don't usually reveal this publicly, but I'm a teenager too. Though I'm certainly not as experienced as people here like sinbad, xavier, etc. (who's opinions btw I greatly respect simply because their experience give it more weight in my opinion), I've been employed professionally as a software engineer for a few years to say the least (currently as a lead 3D engine programmer in the games industry), long enough anyway to know that I don't know everything (there's always more to learn), and that a statement like "singletons are not to be used, period" would be foolish even if it seemed true based on my limited experience.
In summary: You need a global to do the synchronisation, and you need exactly one instance. And that means it's a Singleton. As simple as that.
He just doesn't get it.

nullsquared: As to wikipedia, scroll down a little:
wikipedia wrote:Implementation of a singleton pattern must satisfy the single instance and global access principles. It requires a mechanism to access the singleton class member without creating a class object and a mechanism to persist the value of class members among class objects.
A singleton is essentially a global variable reference to a class, with error checking to crash if more than one instance is created.

CABAListic is correct:
If you use a global for the purpose, then it is still a Singleton, but your code does not enforce the single instance rule
CABAListic
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 2903
Joined: Thu Jan 18, 2007 2:48 pm
x 58
Contact:

Re: Singleton Discussion

Post by CABAListic »

nullsquared wrote: What, are you going to "accidentally" make a second global? :roll:
There are many errors you are not likely to make. And still, you will protect your code against them if possible. The point is that the singleton pattern fits the issue 100% (which is to express a singleton) and, in this case, comes at no cost (since you've failed to name a single disadvantage). You don't need to use a singleton, but your arguments (so far) against using them just don't apply.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Re: Singleton Discussion

Post by nullsquared »

CABAListic wrote:
nullsquared wrote: What, are you going to "accidentally" make a second global? :roll:
There are many errors you are not likely to make. And still, you will protect your code against them if possible. The point is that the singleton pattern fits the issue 100% (which is to express a singleton) and, in this case, comes at no cost (since you've failed to name a single disadvantage). You don't need to use a singleton, but your arguments (so far) against using them just don't apply.
That's only for a log manager. For a log manager, all data goes in, and no data comes out. That's why you can justify a log as a singleton. Though, I still do not see why you would need to make it a singleton instead of simply having a global logger.
JohnJ wrote:
Render system? gfx::renderer has nothing to do with Ogre::RenderSystem. It is what its name implies - a renderer. It abstracts away rendering (for example, I have both a forwardRenderer and a deferredRenderer - the main game can use one, but an in-game computer can use the other).
I knew that. Having both a forwardRenderer and deferredRenderer makes even less sense to me. How do you handle transparency? In my engine it's automatic because it's all managed by one Renderer (not a singleton btw).
Ugh here we go, off topic again. Not both as in at the same time. I can do this:

Code: Select all

if (userSelectedDeferred)
    _renderer.reset(new deferredRenderer(...));
else
    _renderer.reset(new forwardRenderer(...));
Transparency is handled like in any other deferred renderer, via a forward pass for transparent objects.
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 538

Re: Singleton Discussion

Post by Kojack »

To quote the original Gang Of Four book "Design Patterns: Elements Of Reusable Object Oriented Software":
Singleton: Ensure a class only has one instance, and provide a global point of access to it.
CABAListic
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 2903
Joined: Thu Jan 18, 2007 2:48 pm
x 58
Contact:

Re: Singleton Discussion

Post by CABAListic »

nullsquared wrote: That's only for a log manager. For a log manager, all data goes in, and no data comes out. That's why you can justify a log as a singleton. Though, I still do not see why you would need to make it a singleton instead of simply having a global logger.
In summary (as stated before): Automatic self-creation, no explicit setup code necessary, safeguard against multiple instances. If you have no use for either of these, don't use it. I'm not trying to convince you to change your log system. If your system works fine, there's no need to change it. And the same is true for mine. I'd merely like you to take a less fanatical and more pragmatic stance at the issue :)
User avatar
nikki
Old One
Posts: 2730
Joined: Sat Sep 17, 2005 10:08 am
Location: San Francisco
x 13
Contact:

Re: Singleton Discussion

Post by nikki »

So, what nullsquared, do you particularly dislike: Global access, or Singletons (the only-one-instance idea)?

I like global access. :P
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: Singleton Discussion

Post by jacmoe »

If I need a global, I very much prefer a singleton over a plain variable.
You can do a lot with dependency injection, but sometimes a singleton is a better option.
There are a lot of issues with singletons, as we've talked about in previous singleton topics, like hidden dependencies, etc. - but it's there.
Just like static class members are there.
And globals.
Things are easier in Java or C# (where there's no such thing as a non-class object).
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
Klaim
Old One
Posts: 2565
Joined: Sun Sep 11, 2005 1:04 am
Location: Paris, France
x 56
Contact:

Re: Singleton Discussion

Post by Klaim »

That's only for a log manager. For a log manager, all data goes in, and no data comes out. That's why you can justify a log as a singleton. Though, I still do not see why you would need to make it a singleton instead of simply having a global logger.
Well the graphic rendering system interface of the computers my software runs on is unique and accessible as a environnement resources from the code point of view. So I need a Singleton class as interface to this system to reflect the uniqueness and the environemental - global - access. Currently I uses Ogre to do this. I don't allow all the modules of my project to access this singleton class, but the modules that are allowed to access it can use it from anywhere.

I don't see why it would be always a bad idea to use singleton types. As other already pointed, experience shows that each solution is a tool with drawbacks and advantages that you have to understand before mastering it. It's good to experiment extreme rules to understand the drawbacks too, but it's not a good thing to totally adhere to them. We see the points you're making here but they are valid only in a perfect world.
Locked