1

I've been reading the top posts of stackoverflow and SE and all over the place it says how bad singletons are but I am unsure how to rewrite my code.

As of now I have two projects that bind into a gameEngine that each have a singleton class to access the content:

  • Singleton for retrieving/creating an instance of a 3d spatial grid and storing it as the active instance. Futher allows injecting own datatypes that conform to an interface and so can be de/-serialized with custom attributes into that active instance. Adding and removing objects from the active instance and bulk methods for the same thing.

  • Singleton for the main AI loop: Adding/Removing Units from the main AI loop, Injecting/Replacing additions to the main StateMachineProcesses that drive the AI. Most significant, what I hate about this second one: It needs access to the active grid instance from singleton #1 as one of the main aspects of the AI is the awareness of its surroundings and all worldobjects are stored in the database of project number one.

As there should always only be one active instance of these two things, are singletons a neccessity or is there a better way to redesign the whole thing?

2 Answers2

4

Is singleton the right way to go...

No. A stateful, globally accessible, singleton (ie the singleton design pattern) is always an antipattern and there is always a better way of doing things.

The standard way of avoiding those singletons is to use dependency injection (DI). You could still have single instances of certain objects, you just pass them to each object, rather than making them globally accessible.

In your case, you could just go for very simple DI by passing the 3d spatial grid and AI loops to all other objects via their constructors. This is crude, but works around the need for singletons and so would immediately eg improve the ease with which your code can be tested.

David Arno
  • 39,599
  • 9
  • 94
  • 129
-1

There are a few things here.

Firstly, if you have resource heavy component that you only need one (or a limited number) of, then a Singleton pattern is perfectly sensible. As described, your two uses look like good candidates for singletons.

Note, that's not the same as saying they should be globals. That's a different question (which I'll come to). It may be sensible, for example, to have a singleton 3d grid and explicitly pass it to your singleton AI loop.

Having globals is generally a bad idea, or more specifically having mutable globals is a bad idea. As both of your components are clearly mutable this would affect that decision. I won't go into detail about why globals are bad as there is no shortage of commentary on the 'net about this subject.

However, what doesn't often get reported is why you might want to have mutable globals despite their significant downsides.

If you don't have globals, then you have to pass a reference to the object to each function/method that must access it. Evidently, this takes up an argument slot. In certain language ABIs (notably some C and C++), the first few arguments may be passed in registers. Now if you are counting cycles i.e. you have very tight performance constraints, this could be a problem. You may be continually passing a number of references to a number of heavily used functions causing regular register spills and excessive cache misses.

Is this ever a sufficient reason? Yes it can be though in my experience it's quite rare. Interestingly, the most common case I have seen is in game engines where large singletons and tight performance characteristics are endemic.

Should you use globals? Well, that obviously depends on the detail. In most cases I would recommend not to. Even if you do have a need for a global, don't treat it as one except where necessary. In other words, pass it to the functions that use it as an argument except where the performance requirements demand otherwise. Then document the hell out of it.

As with many things in the software world, there are very sensible rules of thumb for singletons and globals but a good engineer knows when to bend them.

Alex
  • 3,942