Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Avoiding 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.

  • You cannot reply to this topic
71 replies to this topic

#1 shurcool   Members   -  Reputation: 439

Like
0Likes
Like

Posted 19 March 2012 - 12:20 PM

I was under the impression that if one had a lot of freedom and time to write high quality C++ code and follow best practices, then one could avoid having global variables altogether. After all, global variables often feel like quick hacks in order to code something up quickly, rather than "take your time and do it properly", and when a project gets larger they get in the way. Often, you'll need to replace a single global class instance with a list of properly maintained objects.

Anyway, if the general idea above is sort of true (that it's better code practice to avoid globals when possible, and it is possible to avoid them in all cases), what happens if...

Suppose you have a list of a lot of items. And each of these items needs to have some sort of connection to the outside world, i.e. for example to the list itself.

If you had a global variable, the problem would be solved trivially. But otherwise, would you have to specify that variable and add it to each instance of your item collection?

struct MyCustomContainer
{
	int Whatever;
	SomeGlobalClass * ConnectionToOutsideWorld;   // This becomes a huge waste of memory because it's there in each instance, only to replace 1 global variable
}
std::vector<MyCustomContainer> LotsOfItems;

Please offer some advice.

Sponsor:

#2 DvDmanDT   GDNet+   -  Reputation: 1191

Like
3Likes
Like

Posted 19 March 2012 - 12:31 PM

Why do all the object need that outside connection? That's the key here. They probably shouldn't. Perhaps they need it for some operation? In that case, pass that data to that operation instead.

#3 shurcool   Members   -  Reputation: 439

Like
0Likes
Like

Posted 19 March 2012 - 12:32 PM

Here's some reference for advocating that global vars can/should be avoided: http://www.gamedev.net/topic/621707-singleton-template/

Basically, my question is this: Do I need to redesign my code so that the items in a huge list do not need a connection to the outside world... Or is there a better solution than to waste memory by padding each item with a variable (which could be replaced by 1 global variable or singleton).

#4 shurcool   Members   -  Reputation: 439

Like
0Likes
Like

Posted 19 March 2012 - 12:32 PM

Ok, let me look up what exactly I was doing that required a connection to the outside. I'm pretty sure it seemed hard not to require it.

#5 shurcool   Members   -  Reputation: 439

Like
0Likes
Like

Posted 19 March 2012 - 12:43 PM

Why do all the object need that outside connection? That's the key here. They probably shouldn't. Perhaps they need it for some operation? In that case, pass that data to that operation instead.

Okay, you were right. They need it for a few operations, and in theory I could be passing the outside-connection variable as a parameter to those functions. But I'll have to start passing it in oh-so-many places which is annoying given how much less typing it'd be to just have a reference.

Basically, I have a WidgetManager class that contains a bunch of instances of classes derived from a Widget class.

The Widget class has functions like CheckHover(), CheckActive() and CheckAnyActive() that return true if the currently hovering/active widget (info available in parent WidgetManager class) happens to be _this_ widget.

bool Widget::CheckHover()
{
return (this == m_WidgetManager.m_HoverWidget);
}
bool Widget::CheckActive()
{
return (this == m_WidgetManager.m_ActiveWidget);
}
bool Widget::CheckAnyActive()
{
return (nullptr != m_WidgetManager.m_ActiveWidget);
}

The classes that derive from Widget (e.g. ButtonWidget and whatnot) use those methods from Widget to do their jobs.

So it looks like I'd have to rewrite those functions as Widget::CheckHover(WidgetManager & WidgetManager), etc. if I want to avoid storing a WidgetManager & m_WidgetManager; variable in each instance of Widget. Of course, in this case there's probably not that many of them, but I just felt it was unnecessary duplication of memory in order to avoid globals...

#6 Madhed   Crossbones+   -  Reputation: 3350

Like
0Likes
Like

Posted 19 March 2012 - 01:02 PM

What about:

Widget::SetHover(bool hovered)

which is called by the window manager.

#7 shurcool   Members   -  Reputation: 439

Like
0Likes
Like

Posted 19 March 2012 - 01:15 PM

What about:

Widget::SetHover(bool hovered)

which is called by the window manager.

A WidgetManager will contain many Widgets. By design, there will at all times be 1 or no hover objects. So it makes sense to have one variable that represents which Widget (if any) is hover.

If each Widget has a bool hover, then:

1. It wastes memory.
2. Due to bugs or memory errors, it may be the case there will be more than 1 Widget with hover set to true, causing further bugs.

I want to follow the DRY principle. If some concept requires only one variable to represent it, I don't see any compelling reason (other than ease of writing code) to use more memory than that to represent it.

#8 e‍dd   Members   -  Reputation: 2105

Like
0Likes
Like

Posted 19 March 2012 - 01:23 PM

Why have a variable at all? Use the mouse-move event to search for the widget under the cursor and tell said widget to do whatever it needs to do due to the on-hover condition.

#9 shurcool   Members   -  Reputation: 439

Like
0Likes
Like

Posted 19 March 2012 - 01:41 PM

There is some state that needs to be kept track of from the past. Current mouse event isn't enough. For example, when releasing the mouse button, it matters where it was clicked to begin with. But this is off topic.

What I'm more interested in knowing is this:

If you have a large list of custom structs that needs an "outside world" connection, there two solutions that use no more memory than is least required:
1. global variable/singleton
2. pass in the variable as a parameter to functions that need it, every time

Any other solutions?

#10 Ravyne   GDNet+   -  Reputation: 9620

Like
4Likes
Like

Posted 19 March 2012 - 01:53 PM

Does the widget need to know that it's hovering? Probably not -- A widget should be concerned only with being a widget, not with how the application presents the widget. If the widget type itself has many states, then track the state internally -- if a collection of widgets can share in some mutual (or mutually-exclusive) state, as in your example, then the widget container is probably the appropriate place to hold that state.

An alternative solution to your problem would be to replace the widget to be hovered with a widget that is inherently hovering, and then to replace the old widget when it looses the hover status.

OOP doesn't state that you should push all state down into the lowest levels that you can, it states that state should exist at the lowest level that is reasonable in order to reduce the visibility of that variable -- its that act that reduces coupling, encourages SRP, and promotes reusability, among other OOP design goals.

#11 L. Spiro   Crossbones+   -  Reputation: 16438

Like
1Likes
Like

Posted 20 March 2012 - 06:50 AM

If you have a large list of custom structs that needs an "outside world" connection, there two solutions that use no more memory than is least required:

It would be easier to answer if you would provide an example of when knowledge of the outside world needs to be known.
If hovering requires special changes to the graphics of the widget, then the widget needs to know it is hovering or not hovering.
If there can be only one widget that can hover at a time, then the manager of the whole set of widgets needs to tell the previously hovering widget that it is no longer hovering (change a state flag) and tell the new one it is. Fairly trivial if the manager simply keeps a pointer to the one widget that is hovering.

Here is the problem.
Let’s assume both of the above rules are necessary, and that is what you tried to explain.
But when you explained it you stated it as a single rule.


It isn’t one rule. It is 2 separate rules localized to the objects that made those rules exist.
If a widget needs to do special rendering for a hover state, then all widgets need a flag for that, since it is their own job to live inside their own little box (with no knowledge of the outside world) and handle the functionality they were meant to handle.

And if only one widget can be hovering, or have focus, or whatever else, then you need to think about who actually made that rule. It certainly wasn’t the widgets themselves.
They live in a box, with no connection to the outside world.
It was the widget manager who decided it could only keep track of one widget having focus or hovering.
It should obviously be the widget manager who tracks that data.


Data about past clicks?
Considering that users could drag from one control and into another, it probably makes the widget manager a good candidate for the task of keeping track of the mouse history.



Basically, if you ever need to ask how to make widgets aware of the outside world, you are doing it wrong, because there is no reason. It should never happen under any circumstances.
So next time you feel the urge to ask that question, consider that it means you have not properly separated the rules for objects and what should handle those rules, and rethink your design.


L. Spiro

#12 shurcool   Members   -  Reputation: 439

Like
0Likes
Like

Posted 20 March 2012 - 09:21 AM

Thanks for your post, YogurtEmperor.

Basically, if you ever need to ask how to make widgets aware of the outside world, you are doing it wrong, because there is no reason. It should never happen under any circumstances.

But what if I want a very basic widget system that encloses all the widget-related code within the widgets. Including rendering, and input handling, both of which require the knowledge of hover/active states. Keeping a bool inside each widget is not an option in my view because it's unnecessary duplication.

The WidgetManager's job is to manage which of its widgets is being hovered (if any), and which one is active (if any).


So next time you feel the urge to ask that question, consider that it means you have not properly separated the rules for objects and what should handle those rules, and rethink your design.

My widget system is rapidly changing as I'm developing it. However, in the process of doing so, I've come up with the previous abstract question and I wanted to ask in order to see what some answers might be.

My current understanding of the best answer: Yes, you can avoid global vars/singletons while maintaining DRY principle. In the case that a large number of instances need access to "the outside world" inside certain functions, then you should pass that reference as a parameter to the function. The main downside is extra typing of code.

#13 shurcool   Members   -  Reputation: 439

Like
0Likes
Like

Posted 20 March 2012 - 09:29 AM

My widget system is rapidly changing as I'm developing it.


As evidence of this, consider that I originally had just one hover/active object per WidgetManager.

Now, I've changed it so that WidgetManager doesn't keep track of one hover/active object, but another class called Pointer does. WidgetManager has a variable number of Pointer instances (typically one). This Pointer represents some abstract input device that has the capability to independently hover or activate Widgets. For example, a mouse pointer. Or a finger touch input. But there might be two finger touches, both of which can be hovering over various widgets. Or a finger plus the mouse pointer.

This redesign allows multiple widgets to be interacted with simultaneously, which is something I wanted to be possible.

#14 Ravyne   GDNet+   -  Reputation: 9620

Like
2Likes
Like

Posted 20 March 2012 - 10:23 AM

Thanks for your post, YogurtEmperor.

Basically, if you ever need to ask how to make widgets aware of the outside world, you are doing it wrong, because there is no reason. It should never happen under any circumstances.

But what if I want a very basic widget system that encloses all the widget-related code within the widgets. Including rendering, and input handling, both of which require the knowledge of hover/active states. Keeping a bool inside each widget is not an option in my view because it's unnecessary duplication.

To be completely blunt, the root of your problems is that your design stinks. You're trying to shoe-horn your problem into your pre-conceived solution and ignoring the fact that all the evidence is waving you off, not to mention us here. That's about as effective as leading a horse by the cart.

Yes, you should be suspicious of duplicated code and duplicated values, but that doesn't mean it should be avoided out-of-hand. Concern yourself with choosing the correct solution, not the one that fits into some notion of being "optimal" in some dimension. In short, what you *think* you want very often turns out to be wrong, and that's especially true with the less experience you have in programming or with a particular type of problem.

So next time you feel the urge to ask that question, consider that it means you have not properly separated the rules for objects and what should handle those rules, and rethink your design.


Quoted for emphasis. Problems lead *you* to the solution, you don't lead problems to the solution.

My current understanding of the best answer: Yes, you can avoid global vars/singletons while maintaining DRY principle. In the case that a large number of instances need access to "the outside world" inside certain functions, then you should pass that reference as a parameter to the function. The main downside is extra typing of code.


That's more-or-less right. However, let me emphasize that parameter passing is a *good* thing -- taking the opposite view corrupts modularity, and all too often leads to half-baked "solutions" like Singleton.

Never let the amount of typing sway you from using parameters -- "less typing" is an excuse used by lazy typists who fancy themselves programmers. The only good thing that has *ever* come out of programmers typing fewer characters is functional programming Posted Image

#15 DemonRad   Members   -  Reputation: 290

Like
-2Likes
Like

Posted 20 March 2012 - 10:35 AM

globals should be avoided. And often CAN be avoided. what about making every ojbect as child of a parent class from wich each child can get all other missing informations?

Peace and love, now I understand really what it means! Guardian Angels exist! Thanks!


#16 VReality   Members   -  Reputation: 436

Like
0Likes
Like

Posted 20 March 2012 - 11:11 AM

Now, I've changed it so that WidgetManager doesn't keep track of one hover/active object, but another class called Pointer does. WidgetManager has a variable number of Pointer instances (typically one). [...snip...] there might be two finger touches, both of which can be hovering over various widgets. Or a finger plus the mouse pointer.

This redesign allows multiple widgets to be interacted with simultaneously, which is something I wanted to be possible.


I think this turn of design illustrates that your initial intuition was a little off. It turns out that Widgets each storing hover state is only redundant in the special case that only one could ever be "hovered" at a time.

I suspect that your concerns about wasted space in the Widgets is unfounded. If you ever have enough of them that you really do need to start worying about their per-instance bytes, then you should re-visit this.

But if you'd still like to be concerned, just for the sake of argument, then you might try this: Decide on a maximum number of simultaneous hovers, and put a static array of references to "hovered Widgets" in the Widget base class (perhaps with accompanying references to respective "Pointer" class objects). That way, all Widgets can look up whether or not they're being hovered (and by which pointer), without adding per-Widget storage.

#17 Cornstalks   Crossbones+   -  Reputation: 6995

Like
0Likes
Like

Posted 20 March 2012 - 11:24 AM

But if you'd still like to be concerned, just for the sake of argument, then you might try this: Decide on a maximum number of simultaneous hovers, and put a static array of references to "hovered Widgets" in the Widget base class (perhaps with accompanying references to respective "Pointer" class objects). That way, all Widgets can look up whether or not they're being hovered (and by which pointer), without adding per-Widget storage.

That's not avoiding a global variable. Static variables pretty much are global variables; they're just in a class and not a namespace.

I think the answer to avoiding global variables in this instance (and some others) is avoiding premature optimization.
[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#18 shurcool   Members   -  Reputation: 439

Like
-1Likes
Like

Posted 20 March 2012 - 11:45 AM

This redesign allows multiple widgets to be interacted with simultaneously, which is something I wanted to be possible.


I think this turn of design illustrates that your initial intuition was a little off. It turns out that Widgets each storing hover state is only redundant in the special case that only one could ever be "hovered" at a time.


It's not really a special case. Unless each and every one of my widgets can be active and hovering independently, it makes no sense to store a bool inside each one.

I suspect that your concerns about wasted space in the Widgets is unfounded. If you ever have enough of them that you really do need to start worying about their per-instance bytes, then you should re-visit this.


It's not about wasting space, it's about duplicating the same piece of information in multiple places - and having to write additional code to maintain a valid in-sync state. Having just one variable to store one piece of independent data solves this problem trivially.

I'm basically explaining DRY here, but consider a situation where you need a single integer variable for storing a single value.

You could do this:

int SomeValue;		  // A single variable
SomeValue = 500;
// Use the variable later on

or this:

int SomeValue[10];		  // 10 copies of the same single variable
for (int i = 0; i < 10; ++i)
	 SomeValue[i] = 500;
// Use 10 copies of the same variable later on (remember, if you want to change the value, you should change all 10 variables)

In this case, it's completely obvious the second solution makes no sense. It duplicates the same information 10 times, without any benefit. It only creates problems, because there's extra effort to write code to keep 10 copies in sync, and to make sure they don't go out of sync. It's bug-prone, as the 10 copies of the same variable might fall out of sync due to a logic bug. It's also more coding effort, which is why no one does this.

That's my motivation for not repeating information in more places than necessary. But in other cases, you have to do more coding effort to maintain a single copy of single piece of data rather than duplicating it, but I think it's worth it in the end.


That's more-or-less right. However, let me emphasize that parameter passing is a *good* thing -- taking the opposite view corrupts modularity, and all too often leads to half-baked "solutions" like Singleton.

Never let the amount of typing sway you from using parameters -- "less typing" is an excuse used by lazy typists who fancy themselves programmers. The only good thing that has *ever* come out of programmers typing fewer characters is functional programming Posted Image

Excellent! That's great news for me and what I wanted to hear.

I am not afraid of extra coding effort/amount of typing required. I just wanted to know, ignoring the implementation effort, if the solution is a more desirable one. The extra coding effort is only a problem in existing IDEs.

#19 VReality   Members   -  Reputation: 436

Like
0Likes
Like

Posted 20 March 2012 - 11:58 AM

Static variables pretty much are global variables; they're just in a class and not a namespace.


It's providing global access to state which makes global variables harmful. The whole point of adding things like static members to C++ is fine control over not just instancing, but access. So, no; Having the same sort of lifetime does not make them the same thing.

Granted, allowing all Widgets access to all hover data is not as safe as hiding data within each Widget instance, but design is about finding the best trade-off for you. In this case, giving access only to the Widgets doesn't seem unreasonable, and is a far cry from global accessibility.

But this approach does add look-up and management cost. Again, if per-Widget space is that important, then maybe it's worth the cost.

#20 VReality   Members   -  Reputation: 436

Like
0Likes
Like

Posted 20 March 2012 - 12:20 PM

Unless each and every one of my widgets can be active and hovering independently, it makes no sense to store [this state data] inside each one.


I don't think this is necessarily true. What if all but one could?

What if 75% could? 50%?

Yeah, there might be a more efficient way to represent the data - some way that has less redundancy - if only one, or only a few can be "active and hovering" at a time (like the way I described above). But only when we limit it to exactly one, can we say that per-Widget state data is completely redundant. And redundant per-Widget data wouldn't really add maintenance complexity.

Anyway, I realize that I didn't really answer the original question. Instead of coming up with a way to give list items access to an external resource, without a reference, I've proposed doing away with the external resource and moving the desired data into static class storage (in the case that every instance of a list item is interested in the same data).

Perhaps a solution more in line with your thinking, if you want some sort of render related processing to go through the Widgets, would be for that processing to go through the Widget Manager first. So instead of some other system telling the Widget to do render processing, and the Widget then looking to the WidgetManager for data, that other system could tell the Widget Manager to initiate processing for all of its Widgets, and the Widget Manager could pass each one whatever additional data it needs.




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.



PARTNERS