Can I avoid using a global?!

M

mike3

Hi.

I've got this problem. I was building a game in C++, and ran into
this, which is causing me some trouble. I was wondering if I could
avoid using a global here since I've heard that globals are "bad".
I've also heard global _functions_ are bad too. If that's the case,
then this seems impossible to do without using one: how can we draw to
the screen, which seems to require a set of screen drawing functions
that you can call from anywhere, or a "singleton" screen object (bad
too!), etc. etc. etc.?
 
I

Ian Collins

Hi.

I've got this problem. I was building a game in C++, and ran into
this, which is causing me some trouble. I was wondering if I could
avoid using a global here since I've heard that globals are "bad".

Global variables are best avoided.
I've also heard global _functions_ are bad too. If that's the case,

It isn't, it's nonsense!
 
M

mike3

Global variables are best avoided.


It isn't, it's nonsense!

Hmm. Now I've got another question. In this program, I have a number
of
objects that represent various parts of the screen to draw in
("windows").
These are "global" to the source code file that handles the display,
but
are not accessed anywhere outside that -- or at least not visibly,
since
there are functions that can be called from outside that use them. Is
this
global bad? If so, what can be done to replace it?

Namely, I've got some stuff like:

--- Code ---
DisplayWindow *msgWnd, *gameWnd, *statsWnd;
("globals" within the source file UH OH)

....
(Functions that use them -- this is all you see from "outside")
void InitializeGameDisplay()
{
....
}
....
--- End code ---

What to do? I suppose one could wrap the whole display as an
object, but that'd be a "singleton", no, and SINGLETONS ARE
BAD just like globals, no?

???
 
I

Ian Collins

Hmm. Now I've got another question. In this program, I have a number
of
objects that represent various parts of the screen to draw in
("windows").
These are "global" to the source code file that handles the display,
but
are not accessed anywhere outside that -- or at least not visibly,
since
there are functions that can be called from outside that use them. Is
this
global bad? If so, what can be done to replace it?

It would be tidier to put them in the unnamed namespace. That way they
really will only be visible in the source file where they are defined.
Namely, I've got some stuff like:

--- Code ---

namespace {
DisplayWindow *msgWnd, *gameWnd, *statsWnd;
}
 
M

mike3

It would be tidier to put them in the unnamed namespace.  That way they
really will only be visible in the source file where they are defined.



namespace {

}

Hmm. But I'm curious: might there be a way that avoids the global
altogether?
Or is this a situation in which a global may really be a good option?
 
G

Goran

Hmm. Now I've got another question. In this program, I have a number
of
objects that represent various parts of the screen to draw in
("windows").
These are "global" to the source code file that handles the display,
but
are not accessed anywhere outside that -- or at least not visibly,
since
there are functions that can be called from outside that use them. Is
this
global bad? If so, what can be done to replace it?

Namely, I've got some stuff like:
-
--- Code ---
DisplayWindow *msgWnd, *gameWnd, *statsWnd;
("globals" within the source file UH OH)

...
(Functions that use them -- this is all you see from "outside")
void InitializeGameDisplay()
{
...}

...
--- End code ---

What to do? I suppose one could wrap the whole display as an
object, but that'd be a "singleton", no, and SINGLETONS ARE
BAD just like globals, no?

???

I don't want to sound patronizing, but given what I think is your
proficiency in programming, you should start building stuff that works
first. You seem to think too much about things that aren't your
primary concern.

That said... Global variables are code obfuscation technique. You
should wrap the display in an object. That object can contain your
windows or whatever. You can add functions to your object, they will
represent what your object can do (their "responsibilities, if you
will). Don't make that display a global object. Rather, declare it
e.g. in main (or whatever is the place that you want to use it), and
(possibly) pass it around, as a parameter, to other places in your
code. That alone beats having global variables. It also gives a
visible data structure to your code ("ah, I see, I have a display, who
has this and that window etc, and I use display in functions 1, 2 and
3), as opposed to not having said structure, but deducting from the
use of said global variables in various places.

Goran.
 
J

Juha Nieminen

mike3 said:
I've got this problem. I was building a game in C++, and ran into
this, which is causing me some trouble. I was wondering if I could
avoid using a global here since I've heard that globals are "bad".
I've also heard global _functions_ are bad too. If that's the case,
then this seems impossible to do without using one: how can we draw to
the screen, which seems to require a set of screen drawing functions
that you can call from anywhere, or a "singleton" screen object (bad
too!), etc. etc. etc.?

You can avoid some (although not all) problems with globals by putting
them inside appropriately-named namespaces.

On situation where I sometimes do this is when I need some compile-time
constants that affect completely separate and independent parts of the
program. When I put such constants in header files, these files double as
very efficient configuration files for the program (which is especially
useful if you are in a project with multiple developers, not all of them
programmers; for example if a level designer or graphics artist would want
to tweak some setting in the program, he can simply open the approperiate
"configuration file", change the values as needed, and hit the build button.)

Such a file would typically look like:

namespace Settings
{
// The width and height of the grid
const int kGridWidth = 15, kGridHeight = 15;

...
}

(Sometimes even if such a constant affects only *one* single part of
the program, perhaps even one single *line*, I put it in such a header
file because, as said, it doubles as a "configuration" file where all
the compile-time settings are grouped for easy tweaking.)
 
F

Fred Zwarts \(KVI\)

"Goran" wrote in message
I don't want to sound patronizing, but given what I think is your
proficiency in programming, you should start building stuff that works
first. You seem to think too much about things that aren't your
primary concern.

That said... Global variables are code obfuscation technique. You
should wrap the display in an object. That object can contain your
windows or whatever. You can add functions to your object, they will
represent what your object can do (their "responsibilities, if you
will). Don't make that display a global object. Rather, declare it
e.g. in main (or whatever is the place that you want to use it), and
(possibly) pass it around, as a parameter, to other places in your
code. That alone beats having global variables. It also gives a
visible data structure to your code ("ah, I see, I have a display, who
has this and that window etc, and I use display in functions 1, 2 and
3), as opposed to not having said structure, but deducting from the
use of said global variables in various places.

Goran.

And the additional advantage is, that if you encounter a situation with two
displays, each display can have its own variables. If global variables are
used you are less flexible in such a situation.
 
G

Goran

Hmm. Now I've got another question. In this program, I have a number
of
objects that represent various parts of the screen to draw in
("windows").
These are "global" to the source code file that handles the display,
but
are not accessed anywhere outside that -- or at least not visibly,
since
there are functions that can be called from outside that use them. Is
this
global bad? If so, what can be done to replace it?

Namely, I've got some stuff like:

--- Code ---
DisplayWindow *msgWnd, *gameWnd, *statsWnd;
("globals" within the source file UH OH)

...
(Functions that use them -- this is all you see from "outside")
void InitializeGameDisplay()
{
...}

Your problems start this function. If you don't call it before any
other function, your code will pretty likely crash (e.g. because it
initializes your "globals", and some other function uses them, and if
Init... wasn't called...). And there's a way to explain, through code
organization, proper call order. E.g.

class GameDisplay
{
private:
DisplayWindow gameWindow, msgWnd, statsWnd;
public:
void Whatever()
{ use gameWnd, msgWnd, statsWnd... }
};

If you do the above, you can't make a mistake and not call Init (Init
just became the constructor of your GameDisplay). So perhaps you
should try this line of thinking.

And then, in your main() (warning: IMAGINARY CODE):

int main()
{
GameDisplay display;
Game game(display);
game.Run();
return EXIT_SUCCESS;
}

Goran.
 
M

mike3

I don't want to sound patronizing, but given what I think is your
proficiency in programming, you should start building stuff that works
first. You seem to think too much about things that aren't your
primary concern.

However, I've already made a fair number of "working" programs. But
does this mean it is OK to use these "bad" things so long as you can
make it work? But what would _maintaining_ that program be like?
That said... Global variables are code obfuscation technique. You
should wrap the display in an object. That object can contain your
windows or whatever. You can add functions to your object, they will
represent what your object can do (their "responsibilities, if you
will). Don't make that display a global object. Rather, declare it
e.g. in main (or whatever is the place that you want to use it), and
(possibly) pass it around, as a parameter, to other places in your
code. That alone beats having global variables. It also gives a
visible data structure to your code ("ah, I see, I have a display, who
has this and that window etc, and I use display in functions 1, 2 and
3), as opposed to not having said structure, but deducting from the
use of said global variables in various places.

Goran.

However, the thing is, the display may be accessed by a great variety
of different functions and objects, especially to print messages. What
should be done? Is it OK to have a "display" parameter to all those
different diverse things?
 
M

mike3

  You can avoid some (although not all) problems with globals by putting
them inside appropriately-named namespaces.

  On situation where I sometimes do this is when I need some compile-time
constants that affect completely separate and independent parts of the
program. When I put such constants in header files, these files double as
very efficient configuration files for the program (which is especially
useful if you are in a project with multiple developers, not all of them
programmers; for example if a level designer or graphics artist would want
to tweak some setting in the program, he can simply open the approperiate
"configuration file", change the values as needed, and hit the build button.)

  Such a file would typically look like:

namespace Settings
{
    // The width and height of the grid
    const int kGridWidth = 15, kGridHeight = 15;

    ...

}

  (Sometimes even if such a constant affects only *one* single part of
the program, perhaps even one single *line*, I put it in such a header
file because, as said, it doubles as a "configuration" file where all
the compile-time settings are grouped for easy tweaking.)

However, as I mention in my second post, these "globals" are only
accessed via certain functions and are not truly "globally" available.
 
M

mike3

Your problems start this function. If you don't call it before any
other function, your code will pretty likely crash (e.g. because it
initializes your "globals", and some other function uses them, and if
Init... wasn't called...). And there's a way to explain, through code
organization, proper call order. E.g.

class GameDisplay
{
private:
  DisplayWindow gameWindow, msgWnd, statsWnd;
public:
  void Whatever()
  { use gameWnd, msgWnd, statsWnd... }

};

If you do the above, you can't make a mistake and not call Init (Init
just became the constructor of your GameDisplay). So perhaps you
should try this line of thinking.

Yes, I know -- I didn't like the "Init()" function there either --
"Init()"
functions are bad.
And then, in your main() (warning: IMAGINARY CODE):

int main()
{
  GameDisplay display;
  Game game(display);
  game.Run();
  return EXIT_SUCCESS;

}

Goran.

Just thought of something like that. But isn't "game" a singleton
there? (a 1-shot object) Or is the "bad" kind of singleton the one
that acts like a type of global (i.e. if "Game game" were outside
main() and accessed all over the program)?
 
G

Goran

Yes, I know -- I didn't like the "Init()" function there either --
"Init()"
functions are bad.



Just thought of something like that. But isn't "game" a singleton
there?

No. Singleton is a design pattern that ensures you can't possibly
have, at any given time, more than one object of a certain type, and
provides a way to access that sole instance. "Game" and "game" aren't
that. Don't equate a singleton with a local variable ;-).
Or is the "bad" kind of singleton the one
that acts like a type of global (i.e. if "Game game" were outside
main() and accessed all over the program)?

Yes. You also seem to equate a singleton with a global variable ;-).
Not the same either.

Goran.
 
S

Stuart Redmann

However, I've already made a fair number of "working" programs. But
does this mean it is OK to use these "bad" things so long as you can
make it work? But what would _maintaining_ that program be like?

Let's put it like this: Getting things to work should be your primary
concern. If you use "bad" techniques, you'll pretty soon experience
some kind of glass ceiling: You'll find that it is getting more and
more difficult to add features to your code.

Whenever you reach such a point you can start to re-design or re-
factor. Of course, this is much more time-consuming than if you had
used better techniques in the first place, but unfortunately humans
learn fastest when they make mistakes ;-) Seriously, finding the
proper design is magnitudes more difficult than getting things just
done. So you'll get discouraged over getting things tidy right from
the start. Most beginners stop working on some project because they
struggle with the wrong objectives (not that I mean that you are a
beginner).

BTW, I'd rather say "inappropriate" techniques, since IMHO there are
no bad techniques, at least not in the sense that a "bad" technique is
a technique that must be avoided at all costs. For example, you can
write pages of code in order to implement a proper thread-safe
singleton, or just use a global variable. Only if the global variable
is not sufficient, you should replace it by something that is more
complicated.



However, the thing is, the display may be accessed by a great variety
of different functions and objects, especially to print messages. What
should be done? Is it OK to have a "display" parameter to all those
different diverse things?

I'd rather use the global variable. Just like std::cout, you'll don't
want to pass around a pointer to std::cout.

That's my 2 cents. (I don't want to start a flame war over this)

Regards,
Stuart
 
G

Goran

However, I've already made a fair number of "working" programs. But
does this mean it is OK to use these "bad" things so long as you can
make it work? But what would _maintaining_ that program be like?

You have to find this out by yourself ;-). Seriously, doing "good"
things means understanding why they are good. One of best ways to find
out why is to do bad things and hopefully learn from mistakes.
However, the thing is, the display may be accessed by a great variety
of different functions and objects, especially to print messages. What
should be done? Is it OK to have a "display" parameter to all those
different diverse things?

Passing a parameter normally beats having a global (sometimes not by
much, though, see below). If nothing else, you can track where things
are used by looking at function signatures (as opposed to chasing down
their uses by reading everything).

About "especially to print messages" part: you should probably think
about that in a more abstract way. Program elements that want to
"print messages" don't really want to print messages. What they really
want is for their messages to go somewhere, and where that is, they
don't really care. They don't care about message window. So you should
probably do exactly that: pass, to those program elements, a facility
that they can use to "send" their messages. E.g.

file: messageReceiver.h
struct IMessageReceiver
{
virtual void Receive(const Message& m) = 0;
};

file: MessageDisplay.h
class MessageDisplay : public DisplayWindow, IMessageReceiver
{
// ...
virtual void Receive(const Message& m)
{
show message...
}
};


file: gameDisplay.h
class GameDisplay
{
MessageDisplay messageWnd;
DisplayWindow gameWindow;
// ...
};

file: partOfTheGame.cpp
void randomFunction(IMessageReceiver& r)
{
workworkwork;
r.Receive(Message("some text", Important));
workworkwork;
}

What I am talking about here is also known as "interface segregation
principle": for a given part of your code, you want to pass in things
it needs to do the work. To do that in a clean way, a good way is to
create the interface (from the rest of your code) to another part, and
pass that interface in. You don't want one big great massive thing
that can do everything, and then cherry-pick what you need from that
great big thing. That's akin to a global variable, except that you
avoided having it as one, by passing it -everywhere- through a
parameter.

Goran.
 
M

mike3

On Nov 22, 11:02 am, mike3 <[email protected]> wrote:

You have to find this out by yourself ;-). Seriously, doing "good"
things means understanding why they are good. One of best ways to find
out why is to do bad things and hopefully learn from mistakes.

However, what if you do the "bad" thing but manage to get away with
it, i.e.
it doesn't cause a problem in the particular program in question?
 
M

mike3

Let's put it like this: Getting things to work should be your primary
concern. If you use "bad" techniques, you'll pretty soon experience
some kind of glass ceiling: You'll find that it is getting more and
more difficult to add  features to your code.

Hence why I'm asking about "good" techniques :)
Whenever you reach such a point you can start to re-design or re-
factor. Of course, this is much more time-consuming than if you had
used better techniques in the first place, but unfortunately humans
learn fastest when they make mistakes ;-)

Oh, because it's not so easy to understand how to do things right,
until
you've done them wrong, and so can see just how it went wrong, right?
Seriously, finding the
proper design is magnitudes more difficult than getting things just
done. So you'll get discouraged over getting things tidy right from
the start. Most beginners stop working on some project because they
struggle with the wrong objectives (not that I mean that you are a
beginner).

Yet if it's "magnitudes more difficult" to "find the proper design",
then how is the "make it work then re-factor/re-design" approach
necessarily "much more time-consuming" than the approach of "use
better techniques in the first place", when to do the latter requires
more time "designing"? In other words, from the way you describe it it
would be roughly equal in time requirements, just proportioned
differently:

1. the first approach takes a "great deal of time", but that great
deal
of time is spent coding/re-coding,

2. the second approach takes a "great deal of time", but that great
deal
of time is mostly spent "designing".
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top