• Create Account

## Ways to avoid the needs and the musts of global variables??

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

87 replies to this topic

### #61ApochPiQ  Moderators

Posted 02 January 2011 - 12:39 PM

I think my real distaste for your attitude stems from your insistence on generalizing from your own experience as if nobody else will ever - should ever - experience anything different.

My point is, briefly, this: maybe it works great for you to do things the way you do. But to assume that your personal path is the optimal route for everyone is the height of both ignorance and arrogance.

These recommendations, best practices, tools - they don't exist because we feel like making a mess of things. They exist because they have concrete benefits to a certain class of people. You sit here and claim not to belong to the class of people who benefit from them; fine. Maybe that's true, maybe you just don't understand them well enough to benefit, I'm not arguing either way here. All I'm saying is that your attitude that nobody else should belong to that class of people is just... disgusting.

To then insinuate that people are unskilled, or unintelligent, or should be fired, or whatnot just for not agreeing with you... that, frankly, makes me feel a little sick.

Sure, maybe you really do find it best to cut your lawn with a toothpick and a butter knife. But don't you dare look down on me for finding it more efficient to use a damned lawn mower.

### #62Rubicon  Members

Posted 02 January 2011 - 12:45 PM

Quote:
 Original post by ApochPiQI think my real distaste for your attitude stems from your insistence on generalizing from your own experience as if nobody else will ever - should ever - experience anything different.My point is, briefly, this: maybe it works great for you to do things the way you do. But to assume that your personal path is the optimal route for everyone is the height of both ignorance and arrogance.These recommendations, best practices, tools - they don't exist because we feel like making a mess of things. They exist because they have concrete benefits to a certain class of people. You sit here and claim not to belong to the class of people who benefit from them; fine. Maybe that's true, maybe you just don't understand them well enough to benefit, I'm not arguing either way here. All I'm saying is that your attitude that nobody else should belong to that class of people is just... disgusting.To then insinuate that people are unskilled, or unintelligent, or should be fired, or whatnot just for not agreeing with you... that, frankly, makes me feel a little sick.
Please stop this. As a moderator you should be fully aware that the whole purpose of a discussion forum is to illicit opinion. I can only offer my own and you can only offer your own and both are valid opinions.

But more than that, stop using emotive language to make me out to be some sort of Hitler. Just because you've read too much into what I say doesn't make you right either.

But just to be plain. I never insinuated anyone is dumb for not agreeing with me. Nor that they should be fired for disagreeing with me. In fact, I didn't say or insinuate any of the things you accuse me of, and I'm calling you out on it. Please fire away with your examples or be quiet.

------------------------------Great Little War Game

### #63ApochPiQ  Moderators

Posted 02 January 2011 - 01:02 PM

Collecting opinions is fine. But the fact of the matter is that some opinions are dangerous and potentially damaging to the people most interested in hearing them; I feel that yours belong to that category. The notion that all opinions are equally valid is borne of the same immaturity as a schoolchild's insistence that everything should be "fair."

Anyways, you asked for examples of the things I'm accusing you of saying. Fair enough. I don't think I read too far into any of this, though; if anything, I'm doing the best I can to give you the benefit of the doubt.

Quote:
 Original post by Rubicon"Just get it done" is the most important factor in a programmers make up, but this goes totally unsaid. Well, unsaid by those that don't actually think it's top of the list and are therefore just seat filling drones- and those guys should just do what they're bloody well told.

Quote:
 Original post by Rubiconif there are programmers in an outfit that pass a null into a function which then crashes and they can't figure out why that is and fix it quickly, they should get fired.

Quote:
 Original post by RubiconIf we ever ran into these notional problems that advocates dream up, then we'd probably re-examine our working practices. However they just don't. So we get on with churning out perfectly fine working code and f**k the standards comittees and globals police.

Quote:
 Original post by RubiconAnd just to finish off, what the hell is a unit test anyway? (rhetorical) I think I can guess and it sounds an awfully tedious way to avoid getting work done to me. If anyone asked me what our unit testing practices were in an interview, the very next thing to happen is me saying "thanks for your time" and handing him his train fare. We don't write unit tests, we write games.

I didn't even have to try to dig to find those, and they're all from this thread.

### #64Rubicon  Members

Posted 02 January 2011 - 01:24 PM

But the way you are painting me is of course perfectly fair. okay, getting the rules now. And please don't "give me the benefit of the doubt" whilst lecturing about condescension

I see a load of random quotes by me above, but nothing that backs up your claim that I insinuate or downright assert that disagreeing with me is either dumb or should get you fired.

The "drones" comment is admitedly a bit harsh, and I'll even go so far as to admit I shouldn't have said that. But it's still nowhere near what you are claiming.

I think an apology is due, but we all know there won't be one as you now have a bee in your bonnet.
------------------------------Great Little War Game

### #65TheTroll  Members

Posted 02 January 2011 - 01:26 PM

I guess I will jump in this really quickly.

There is a huge difference between writing a game (in which much of the code will never be used again), and writing an application that is going to be maintained for many many years.

Maintaining code takes a different mindset then just creating code. Writing code that is easy to maintain is a whole different beast. I come from application dev world in which we know we will be working on this code base for a long long time.

Unit tests, pattern dev, inheritance patterns are all things that can be used to make that whole process easier. Now there is something to say about getting the product out the door, but when you have to start working on that upgrade that people are going to pay about 1/4th of the original price, you need to have everything in place to make sure you can get it done without all the issues that could come up by just "getting it shipped".

Any time I have worked on a new project I was one of the ones that forced to issue to make sure we did it "right", instead of just getting it done. Did I ever regret that extra time spent? Not once.

To the main topic on here; globals. It all depends. A global that is set at start up and only read from is not really an issue. A global that can only be changed by a single object, is not really a problem. Globals that can be changed by anything at anytime are just not a lot of fun to debug.

theTroll

### #66phantom  Members

Posted 02 January 2011 - 01:38 PM

Quote:
 Original post by TheTrollThere is a huge difference between writing a game (in which much of the code will never be used again), and writing an application that is going to be maintained for many many years.

The problem is if the game does well and a sequal is created sudden all that 'code we are never going to use again' becomes 'code which makes you want to stab the guy who wrote it in the eyes'.

We are dealing with this right now at work; various systems in the game were written to 'just work' and 'get out the door' (on a game which slipped by a year at that); one year after that, when the guy who wrote it had left, the rest of us (me as a new hire onto the team) were left to deal with code which, frankly, only just held together.

Systems with magic numbers all over them and no clue as to what they did; systems which only worked due to the way the old data was setup by the guy who original made it with undocumented limits which took one guy around two weeks to track down and figure out! Overly complicated system which could be reduced in complexity (and as a team we have vowed to rip them out and start again!) and fall apart at the slightest proding.

The idea of writing code like it'll never be touched again just makes me shake my head; unless what you do flops there really is no such thing.

### #67TheTroll  Members

Posted 02 January 2011 - 01:41 PM

Yeah, I know, I was trying to explain the mindset.

I pretty much try to never write code that I wouldn't want to use again.

theTroll

### #68phantom  Members

Posted 02 January 2011 - 01:43 PM

Yeah, wasn't meant as an attack or anything, more to highlight the dangers of such mindsets in general [smile]

### #69Rubicon  Members

Posted 02 January 2011 - 01:51 PM

I should probably state at this point that "just make it work", at least from my mouth, does not mean "bodge it quickly".

What I'm really on about is to write some code to turn the wheels and make it a method called CCar::TurnWheels(float dt);

As opposed to thinking about what refactoring I can do to enable me to inherit CWheel from CCarPart and then consider a design pattern that best serves a wheel turning scenario and then unit testing whether it worked or not. By the time you've read that sentence, I would have my wheels turning. Well, ok. Ish! :)

And by global variable being ok, I mean TimeMgr=Engine->GetTimeMgr(); and not "Sprite[2].x++;"
------------------------------Great Little War Game

### #70return0  Members

Posted 02 January 2011 - 02:00 PM

ApochPiQ, I think I am more aligned with your thoughts on engineering but I don't think you're necessarily being fair on Rubicon. I also happen to disagree with him a lot of the time, but that doesn't mean that his position is not legitimate, or that he is in any way trying to be vindictive.

This thread has covered a decent spectrum of opinions on the OP's topic, and has been quite interesting. I think it has also been useful because it shows the degree to which competent (if competence is dubiously defined as the ability to remain employed and ship/deploy games) disagree about fairly fundamental things, which probably isn't something that a new programmer would necessarily expect.

On that note, I've worked with people I've strongly disagreed with about many engineering practices, and the thing that I've learned is that you can't take it personally... it is frustrating to not "win" the intellectual argument, but that either means I'm wrong or that I'm not good enough at explaining my position.

### #71Rubicon  Members

Posted 02 January 2011 - 02:20 PM

Thanks mate. It's restored the faith a bit to have an old sparring partner put his head above the parapet.

And I never actually expect to win one of these things. I do believe I'm right (or at least I have one version of arguably many rights), but I clearly never present my point the correct way as my main thrust is "get more done with less" which I would've thought should go down better that this! :)

------------------------------Great Little War Game

### #72typedef struct  Members

Posted 02 January 2011 - 02:44 PM

This thread might have run out of steam but let me throw in my bit.

I avoid global variables by not having any global variables.

Global variables are bad because globally mutable state is really really bad. What doesn't have state? Functions. Wait I need state somewhere! Static variables. No one complains about calling rand() from anywhere, though of course it stores state. The state is static, it can only be touched in that module (local, not global).

So the answer to the "global logger" scenario is:
void log_init(settings);void log_print(stuff);void log_shutdown();

If you need more than one, then it's not global anymore, and you need to handle the state.

If you need unit tests, just make an implementation of that module header that does nothing or has sane defaults.

### #73phantom  Members

Posted 02 January 2011 - 03:06 PM

Ugh.. I shouldn't, but sleep isn't calling me yet so...

Quote:
 Original post by RubiconWhat I'm really on about is to write some code to turn the wheels and make it a method called CCar::TurnWheels(float dt); As opposed to thinking about what refactoring I can do to enable me to inherit CWheel from CCarPart and then consider a design pattern that best serves a wheel turning scenario and then unit testing whether it worked or not. By the time you've read that sentence, I would have my wheels turning. Well, ok. Ish! :)

Here that sound? It's the sound of everything you just said wooshing over your head because you are CLEARLY commenting on things you do not understand and that alone makes your advice suspect at best.

I mean, seriously, that sentence (for lack of a better term) was nothing more than technical gibberish at best.

Lets try and take each thing you apprently have a problem with here;
- Refactoring; a process which happens AFTER THE FACT to remove redundant code and clean up intent. This isn't something you'd do before writing the 'TurnWheel' function anyway.

- Inhertiance; often abused, sure, but modern thinking has very much pushed away from this to composition. You'll probably say this is nothing new and I'd agree and beyond short related chains I prefer to avoid it anyway. Frankly anyone who knows anything wouldn't advocate CWheel:CCarPart anyway unless there was very solid reasoning for linking the two types. Maybe the uni graduates you have a bee in your bonnet about would try to do such a thing but not those of us who you also seem to think are 'wrong'.

- Design Patterns; seriously, stop even trying with this you are just showing your ignorance constantly. Design Patterns are nothing more than a common language used to talk about things. A good programmer would be aware of them but wouldn't say "I need to do X, what pattern can I use?" they would say "I need to do X, how can I solve it?" and then later, when discussing it with someone else might say "Yeah, I used a flyweight for that" or "I hooked it up as an observer to do....".

- Unit testing; Again, something you don't understand and yet feel qualified to 'poo poo' as much as possible. If you knew anything about it you'd realise that a unit test for something like that could be a simple as;

-- Set wheel to known rotation
-- Apply function with known time step
-- Check that wheel position is at expected location

Or; set number, call function, compare number.

Finally, as I think I mentioned before; you do not unit test everything. Many things, by their nature, can't be tested. Other things should be tested because you need to check they are still performing to spec. Writing a test for a critical component is generally trivial and testing in general is VITAL for any large project where a bug could be introduced so it can be caught early.

So, here is a suggestion from one professional to another; if you want to rubbish as subject at least have the decency to learn about it first. Attacking something from a position of ignorance (which is what you are doing) just makes you, the attacker, appear ignorant.

Don't want to learn about it?
Fine.
What to continue saying "Well, I don't use this"?
Fine.
Just, you know, drop the "its clearly rubbish, despite the fact I don't know anything about it" line.

### #74phantom  Members

Posted 02 January 2011 - 03:09 PM

Quote:
 Original post by CadetUmferNo one complains about calling rand() from anywhere, though of course it stores state. The state is static, it can only be touched in that module (local, not global).

You know, this makes me wonder how 'rnd' would react when being called from multiple threads at around the same time?
I wonder if the CRT is thread safe in that case...

### #75return0  Members

Posted 02 January 2011 - 03:12 PM

Quote:
 Original post by CadetUmferThis thread might have run out of steam but let me throw in my bit.I avoid global variables by not having any global variables.Global variables are bad because globally mutable state is really really bad. What doesn't have state? Functions. Wait I need state somewhere! Static variables. No one complains about calling rand() from anywhere, though of course it stores state. The state is static, it can only be touched in that module (local, not global).So the answer to the "global logger" scenario is:*** Source Snippet Removed ***If you need more than one, then it's not global anymore, and you need to handle the state.If you need unit tests, just make an implementation of that module header that does nothing or has sane defaults.

Or, store the state in private member variables of an object, "init" it in the constructor, "shut_down" in the destructor/dispose, and have a well defined API. Create these objects where needed. Then invert that dependency.

Now it's impossible to call "Log" before "Init". Yay!

### #76typedef struct  Members

Posted 02 January 2011 - 03:13 PM

Quote:
 Original post by phantomYou know, this makes me wonder how 'rnd' would react when being called from multiple threads at around the same time?I wonder if the CRT is thread safe in that case...

Thread safety is not something that needs to be checked for or handled in code. That's a documentation issue.

For example, the .NET CRT specifies that all static functions are thread safe, member functions aren't. If you call a instance functions from different threads, that's on you. (Well debug mode will probably catch you because they put checks in for it). In C, rand() just isn't thread safe, and they're not babying you if you forget.

So if you want your logger to be thread safe, you document that, and put locks/etc INSIDE the module. The interface doesn't change and the calling code knows nothing about it.

Quote:
 Original post by return0Or, store the state in private member variables of an object, "init" it in the constructor, "shut_down" in the destructor/dispose, and have a well defined API. Create these objects where needed. Then invert that dependency. Now it's impossible to call "Log" before "Init". Yay!

What? My modules often have a static bool init (or more often a state enum) that you can check in your global functions to make sure that the module is in the proper state to execute the function.

It doesn't need to be a "private member variable of a global singleton instance" to do that.

### #77phantom  Members

Posted 02 January 2011 - 03:29 PM

Quote:
 Original post by CadetUmferIn C, rand() just isn't thread safe, and they're not babying you if you forget.

Sorry, I probably wasn't being clear; the quoted bit was what I was simply pondering on. I'd never looked into what the C Runtime Time had to say with regards to thread safety of that function and had never considered the 'static' nature of its operation in that way.

Nothing more than a pondering on my part [smile]

(For the record, when it comes to designing my own stuff I'm well aware of the thread safety requirements of things [smile])

### #78return0  Members

Posted 02 January 2011 - 03:38 PM

Quote:
Quote:
 Original post by phantomYou know, this makes me wonder how 'rnd' would react when being called from multiple threads at around the same time?I wonder if the CRT is thread safe in that case...

Thread safety is not something that needs to be checked for or handled in code. That's a documentation issue.

For example, the .NET CRT specifies that all static functions are thread safe, member functions aren't. If you call a instance functions from different threads, that's on you. (Well debug mode will probably catch you because they put checks in for it). In C, rand() just isn't thread safe, and they're not babying you if you forget.

So if you want your logger to be thread safe, you document that, and put locks/etc INSIDE the module. The interface doesn't change and the calling code knows nothing about it.

Quote:
 Original post by return0Or, store the state in private member variables of an object, "init" it in the constructor, "shut_down" in the destructor/dispose, and have a well defined API. Create these objects where needed. Then invert that dependency. Now it's impossible to call "Log" before "Init". Yay!

What? My modules often have a static bool init (or more often a state enum) that you can check in your global functions to make sure that the module is in the proper state to execute the function.

It doesn't need to be a "private member variable of a global singleton instance" to do that.

I'm not advocating a singleton, or a global instance. That would be insane. I'm advocating using an object, and injecting it where required. Then you don't need to "check static state flags" in global functions because you know it's in a good state. The runtime guarantees it.

### #79Oberon_Command  Members

Posted 02 January 2011 - 03:43 PM

Quote:
 Original post by phantom- Design Patterns; seriously, stop even trying with this you are just showing your ignorance constantly. Design Patterns are nothing more than a common language used to talk about things. A good programmer would be aware of them but wouldn't say "I need to do X, what pattern can I use?" they would say "I need to do X, how can I solve it?" and then later, when discussing it with someone else might say "Yeah, I used a flyweight for that" or "I hooked it up as an observer to do....".

Just going to jump in on this point. I'm currently in my 3rd year of a computer science degree at a university I'd consider decently reputable. Given what I've seen of my fellow students, many of them probably WOULD fall into the sort of thinking that results in "I need to do X, what pattern can I use?" In fact, I think I've overheard almost exactly that quote during an in-class exercise, and both my midterm and final in my 3rd-year level software engineering course had an exam question (if not more than one!) that was basically "you need your program to do X, which of the following patterns would be best used here?" Now, mind you, the professor never explicitly encouraged this kind of thinking - but it would be difficult, given the material presented, to develop any other kind.

If this goes on at other institutions, then Rubicon's example, though obviously exaggerated and invalid at face value, is nevertheless an accurate portrayal of the way many of these people think. If my experience is anything to judge by, then many new graduates are not going to realize that design patterns are descriptive instead of prescriptive. My point is that if Rubicon's sole experience with "design patterns" is through these graduates, I would say that he's not to entirely blame for his warped perspective of them and the distaste for them that accompanies it. One might argue that he is to blame for not going out and educating himself on the matter, however. I had much the same view of design patterns before I learned better (by reading a thread here on GDNet, oddly enough).

### #80typedef struct  Members

Posted 02 January 2011 - 03:46 PM

Quote:
 Original post by return0I'm not advocating a singleton, or a global instance. That would be insane. I'm advocating using an object, and injecting it where required. Then you don't need to "check static state flags" in global functions because you know it's in a good state. The runtime guarantees it.

Sure that's great. But we're talking about replacing something that was in global scope. The decision to put it in global scope was probably made because so many objects need access to it.

Yeah, you can have one single instance (managed/owned sanely, not as a singleton) and pass that around if you need that flexibility. But if that flexibility isn't worth it, use global functions with local state.

I equate it to logging in .NET. There are lots of nice logging frameworks that will do all sorts of cool stuff via dependency-injection. There's also Trace.WriteLine, which will write to a file or a console or a custom TraceListener that you make, so it covers 80% of the use cases.

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.