Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411490 Posts in 69371 Topics- by 58428 Members - Latest Member: shelton786

April 25, 2024, 12:15:30 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Global variables in a C++ project
Pages: 1 [2] 3
Print
Author Topic: Global variables in a C++ project  (Read 5350 times)
ham and brie
Level 3
***



View Profile
« Reply #20 on: September 03, 2013, 06:16:26 AM »

Discounting the instantiation restriction, singletons are really little more than thinly veiled globals anyway, they dont in any way solve any of the issues associated with global state.  Many people use (or advice use of) singletons not because they want to restrict instantiation but simply because they want the simplicity of global access but they've heard that globals are bad.  If you're using singletons in this way you're not actualy solving anything, but you're placing additional restrictions on your project that likely aren't necessary and could be problematic in the future.  Stop lying to yourself and just use a global, or if you are concerned about global state then use dependancy injection or a factory pattern.  Singletons are only appropriate in the case were you really do need to restrict instantiation to one object instance.

There's one advantage you seem to be overlooking: if you need a global to be initialised before it is first used, a singleton can take care of that without you needing to manually maintain the order the global resources are initialised in.
Logged
motorherp
Level 3
***



View Profile
« Reply #21 on: September 03, 2013, 06:22:06 AM »

But how difficult is it to initialise your globals at the beginning of your main function?  Hardly a good reason to misuse the pattern.
Logged
ham and brie
Level 3
***



View Profile
« Reply #22 on: September 03, 2013, 06:48:12 AM »

Harder than not needing to maintain a manual order. If something changes such that the order needs to change (code is added that means one system now uses another system it didn't before) it's not just a case of moving one later or the other earlier, you also potentially need to reorder anything that was between those two.

It's a perfectly acceptable reason to use the pattern.
Logged
motorherp
Level 3
***



View Profile
« Reply #23 on: September 03, 2013, 07:00:46 AM »

You can easily have lazy initialisation without having to make everything a singleton, so no its still not really an acceptable reason to use a singleton unless you specifically need to restrict instantiation.
Logged
Daid
Level 3
***



View Profile
« Reply #24 on: September 03, 2013, 12:17:45 PM »

Harder than not needing to maintain a manual order. If something changes such that the order needs to change (code is added that means one system now uses another system it didn't before) it's not just a case of moving one later or the other earlier, you also potentially need to reorder anything that was between those two.

It's a perfectly acceptable reason to use the pattern.
These dependencies are usually far and in-between. And doing "manual" initialization ensures that you know what is happening instead of relying on complex behavior.

Not to mention all kinds of complexity you can introduce if you have a multi-threaded application. See: http://en.wikipedia.org/wiki/Double-checked_locking

Finally you might be introducing circular problems. Depending on how you setup your singletons you could be creating 2 objects or using an object which is not fully finalized.


No matter which method you use, you still need to take care. Thinking "I'm using a singleton, now my problems are solved!" could make things even worse.
Logged

Software engineer by trade. Game development by hobby.
The Tribute Of Legends Devlog Co-op zelda.
EmptyEpsilon Free Co-op multiplayer spaceship simulator
ham and brie
Level 3
***



View Profile
« Reply #25 on: September 03, 2013, 12:35:12 PM »

No matter which method you use, you still need to take care. Thinking "I'm using a singleton, now my problems are solved!" could make things even worse.

No one ever said anything like that.

All I was pointing out is that motorherp was not giving the full story by neglecting an advantage of using singletons.

I actually agree that singletons are put forward too often irrationally as a kind of way to make a global not a global. However, I think you and motorherp have probably swung too far the other way, too keen to think they're misused.
Logged
motorherp
Level 3
***



View Profile
« Reply #26 on: September 03, 2013, 01:34:54 PM »

Its a case of using the right tool for the job.  For example, if what you're after is lazy initialisation then there's patterns or methods you can use which are specifically designed to achieve that task.  Similarly if all you're after is a way to easily access your objects globally, or to ease the task of setting up dependencies without using injection then there are patterns and methods specifically designed for those tasks too.  The primary purpose of singletons is to restrict instantiation.  Unless that is your goal then using a singleton purely for its by-products is a misuse since you're placing additional restrictions on your design that aren't necessary as well as potentially causing other kinds of dependency issues.

What gets me about singletons especially though is that I see people promoting and defending their misuse all the time, far more than any other pattern, which isn't helpful to people learning to code.  I think one of the issues is that singletons are simple and come with a lot of convenience which is why people get so attached to them, but because of that I also see them being used like a crutch to cover up or get around poor code design.  The thing is though that there isn't a single convenience feature of singletons that are unique to singletons and cant be replicated using other patterns especially designed for those tasks which ultimately promote better code design.

I'm not trying to demonise singletons or their use here.  If you want to use them as a crutch then be my guest, I've done it plenty of times before myself.  Just realise though that you are misusing them in ways which can cause issues and promote bad design.  Singletons are really good at hiding bad design so don't preach their misuse to others trying to learn.
« Last Edit: September 03, 2013, 01:49:13 PM by motorherp » Logged
ham and brie
Level 3
***



View Profile
« Reply #27 on: September 03, 2013, 02:11:15 PM »

Unless that is your goal then using a singleton purely for its by-products is a misuse since you're placing additional restrictions on your design that aren't necessary as well as potentially causing other kinds of dependency issues.

This isn't true. This is a wider point than the one I wanted to make, but I think you're misguided in viewing a restriction as bad unless it's necessary. You could turn that around and ask why you would allow multiple instances unless it was necessary. The real question is not whether the restriction is necessary but whether it is beneficial, which a restriction may well be.
Logged
motorherp
Level 3
***



View Profile
« Reply #28 on: September 03, 2013, 02:27:05 PM »

By using a pattern specifically designed to achieve my goal rather than misusing a singleton where its not strictly needed I have the choice to have a single or multiple instances at any time during my projects development, or any subsequent projects which re-use that code.  By using a singleton I don't have that choice however, and removing those singletons should I later need multiple instances can take a lot of effort.  So yes I do think that placing restrictions on your project which aren't necessary is a bad thing. 

That isn't the only issue with their misuse though but also that it can promote bad design as I was trying to get across earlier.  When people use their convenience features such as global access and lazy initialisation simply because they all come bundled up as side products (especially people learning), then they stop thinking about the effects that is having on their projects dependencies and global state.  At least if you are using patterns and methods specifically for those certain convenience features it is because you have made a conscious design decision to do so and you are thinking about the implications that has on your project.  That could save you a lot of pain further down the road.
Logged
ham and brie
Level 3
***



View Profile
« Reply #29 on: September 03, 2013, 02:32:46 PM »

So yes I do think that placing restrictions on your project which aren't necessary is a bad thing.

Do you? Have you really thought that statement through? Do you understand why language features like const or private are used even when they aren't necessary?

How do you feel about this article?
Logged
motorherp
Level 3
***



View Profile
« Reply #30 on: September 03, 2013, 02:38:23 PM »

But features such as const and private generally are necessary when they are used.  There's usually a very specific reason for you not wanting external classes directly changing your data whenever it wants.  However if there is not a specific reason to disallow multiple instantiations of a class then why would I place that restriction on it?  What benefit does that serve?
Logged
ThemsAllTook
Administrator
Level 10
******



View Profile WWW
« Reply #31 on: September 03, 2013, 03:03:14 PM »

Out of curiosity, are you both talking about the strict sense of the singleton pattern, which explicitly disables multiple instantiation? I've seen the pattern applied in such a way that you can instantiate the object yourself if you want to, but there's a globally-accessible shared instance which initializes itself the first time it's accessed.

I've done too much test driven development to be comfortable using either the strict or the relaxed version of the pattern. The use case for it (needing to absolutely ensure that only one instance of something exists) has never come up in practice for me in all my years of programming, and it's hard to think of a non-contrived situation where it would. Dependency injection is far more flexible and modular, and it allows you to substitute a stub object in place of the would-be singleton for the purpose of unit testing.
Logged

motorherp
Level 3
***



View Profile
« Reply #32 on: September 03, 2013, 03:17:59 PM »

Well I was thinking of the strict version since that's what I always encounter when I see people using singleton patterns.  To be honest I've never come across the relaxed version, but it sounds like a bit of a non-pattern to me.  Generally speaking anyway I agree with you about using dependency injection, or if you find that the amount of injection needed is getting silly because you have some deep hierarchies that you cant flatten or whatever then a factory pattern can be used to ease the burden.  Regarding the original point of the OP wishing to have global access however, my point was that a singleton pattern as was suggested isn't a good solution just for solving that specific issue.
Logged
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #33 on: September 03, 2013, 04:16:22 PM »

Singletons are just fancy object-oriented dressing over modules.  I've never seen a singleton that couldn't be better and more simply implemented as a module.

And lazy initialization isn't an exclusive property of singletons, it can be just as easily done with modules.  To be honest, I can't think of a single scenario in which I would want lazy initialization, so the point is moot for me.

Singletons are an artifact of the Java-powered, "everything is an object!" 90s.  Not everything is an object.  It's OK to let the OOP go sometimes.
Logged



What would John Carmack do?
Daid
Level 3
***



View Profile
« Reply #34 on: September 04, 2013, 08:42:48 AM »

How do you feel about this article?
Instead of "future-programmers" I usually call those people Java-Programmers. Java-Programmers seem to be very keen at over-designing stuff. I have seen a Factory-Singleton-Factory in a simple live Java program...
Logged

Software engineer by trade. Game development by hobby.
The Tribute Of Legends Devlog Co-op zelda.
EmptyEpsilon Free Co-op multiplayer spaceship simulator
InfiniteStateMachine
Level 10
*****



View Profile
« Reply #35 on: September 04, 2013, 11:36:07 AM »

Harder than not needing to maintain a manual order. If something changes such that the order needs to change (code is added that means one system now uses another system it didn't before) it's not just a case of moving one later or the other earlier, you also potentially need to reorder anything that was between those two.

It's a perfectly acceptable reason to use the pattern.
These dependencies are usually far and in-between. And doing "manual" initialization ensures that you know what is happening instead of relying on complex behavior.

Not to mention all kinds of complexity you can introduce if you have a multi-threaded application. See: http://en.wikipedia.org/wiki/Double-checked_locking


Isn't the whole point of double checked locking to eliminate the issues with multi-trheaded applications while at the same time mitigating the performance hit of using a lock?

Out of curiosity, are you both talking about the strict sense of the singleton pattern, which explicitly disables multiple instantiation? I've seen the pattern applied in such a way that you can instantiate the object yourself if you want to, but there's a globally-accessible shared instance which initializes itself the first time it's accessed.

I've done too much test driven development to be comfortable using either the strict or the relaxed version of the pattern. The use case for it (needing to absolutely ensure that only one instance of something exists) has never come up in practice for me in all my years of programming, and it's hard to think of a non-contrived situation where it would. Dependency injection is far more flexible and modular, and it allows you to substitute a stub object in place of the would-be singleton for the purpose of unit testing.

Also out of curiosity. Something like a Texture Manager, Sound Manager, and generally resource managers. In a typical game scenario why would you want more than instance to be available?
« Last Edit: September 04, 2013, 11:51:34 AM by InfiniteStateMachine » Logged

Daid
Level 3
***



View Profile
« Reply #36 on: September 04, 2013, 12:46:40 PM »

Harder than not needing to maintain a manual order. If something changes such that the order needs to change (code is added that means one system now uses another system it didn't before) it's not just a case of moving one later or the other earlier, you also potentially need to reorder anything that was between those two.

It's a perfectly acceptable reason to use the pattern.
These dependencies are usually far and in-between. And doing "manual" initialization ensures that you know what is happening instead of relying on complex behavior.

Not to mention all kinds of complexity you can introduce if you have a multi-threaded application. See: http://en.wikipedia.org/wiki/Double-checked_locking


Isn't the whole point of double checked locking to eliminate the issues with multi-trheaded applications while at the same time mitigating the performance hit of using a lock?
Go back to the page and read all of it. It highlights all the issues with double-checked-locking.
I mean, the article starts out with "The pattern, when implemented in some language/hardware combinations, can be unsafe. At times, it can be considered an anti-pattern."
Logged

Software engineer by trade. Game development by hobby.
The Tribute Of Legends Devlog Co-op zelda.
EmptyEpsilon Free Co-op multiplayer spaceship simulator
ThemsAllTook
Administrator
Level 10
******



View Profile WWW
« Reply #37 on: September 04, 2013, 12:56:00 PM »

Also out of curiosity. Something like a Texture Manager, Sound Manager, and generally resource managers. In a typical game scenario why would you want more than instance to be available?

In a typical game scenario you wouldn't, but for unit testing you would want to pass a stub in place of the texture/sound/resource manager object to each module that uses them, and use the stub to ensure that they're using the API the way you expect. Without unit tests you're not likely to ever need more than one.
Logged

InfiniteStateMachine
Level 10
*****



View Profile
« Reply #38 on: September 04, 2013, 05:01:46 PM »

Harder than not needing to maintain a manual order. If something changes such that the order needs to change (code is added that means one system now uses another system it didn't before) it's not just a case of moving one later or the other earlier, you also potentially need to reorder anything that was between those two.

It's a perfectly acceptable reason to use the pattern.
These dependencies are usually far and in-between. And doing "manual" initialization ensures that you know what is happening instead of relying on complex behavior.

Not to mention all kinds of complexity you can introduce if you have a multi-threaded application. See: http://en.wikipedia.org/wiki/Double-checked_locking


Isn't the whole point of double checked locking to eliminate the issues with multi-trheaded applications while at the same time mitigating the performance hit of using a lock?
Go back to the page and read all of it. It highlights all the issues with double-checked-locking.
I mean, the article starts out with "The pattern, when implemented in some language/hardware combinations, can be unsafe. At times, it can be considered an anti-pattern."

I read the original paper way back so I refrained from reading that article. So according to that article there are only issues with certain languages/hardware.

EDIT: Here's an article by Andrescu that explains it in more detail

http://erdani.com/publications/DDJ_Jul_Aug_2004_revised.pdf

Also out of curiosity. Something like a Texture Manager, Sound Manager, and generally resource managers. In a typical game scenario why would you want more than instance to be available?

In a typical game scenario you wouldn't, but for unit testing you would want to pass a stub in place of the texture/sound/resource manager object to each module that uses them, and use the stub to ensure that they're using the API the way you expect. Without unit tests you're not likely to ever need more than one.

Ah ok I see. I have little experience using unit tests and no experience writing unit tests so a lot of those implications are not immediately clear to me.
« Last Edit: September 04, 2013, 05:07:59 PM by InfiniteStateMachine » Logged

Gregg Williams
Level 10
*****


Retromite code daemon


View Profile WWW
« Reply #39 on: September 04, 2013, 10:13:51 PM »

Yeah if you plan to do unit tests, something like the service locator pattern can be a nice replacement for singletons. Or you could just not have unit tests.. Smiley
Logged

Pages: 1 [2] 3
Print
Jump to:  

Theme orange-lt created by panic