There is a concept in development called an infinite loop. It simply means that a loop runs forever without end. In general, you’d expect that to have an infinite loop situation in your code, you’d need a loop in your code.
Something like:
while( true )
{
// do something
}During a bit of refactoring I accidentally created an infinite loop that didn’t involve any loops. Well, at least not any obvious ones.
The next concept is a singleton. This is a piece of code that guarantees on its own that there can never be more than a single copy of itself. (Thus the name.) It does this by a combination of not allowing other pieces of code to create a copy, and maintaining the only copy allowed internally. Singletons are great for things that you need to be available anywhere in the code, but also need to have state. A great example would be something that loads configuration from storage and then makes it available to anyone that asks for it without the need to load it again.
I had revised something in the code to be a different kind of singleton than it was before (previously Godot Node based, and didn’t really want that anymore) and in the process I created an infinite loop where no loops were involved. Sorry that the formatting for the following code is very squished, but can you see the infinite loop?
public class Singleton {
private DataType data = null;
private static Singleton inst = null;
private Singleton() { LoadData(); }
private static Singleton GetInst() {
if( inst == null ) inst = new Singleton();
return inst;
}
public static DataType Data { get {
return GetInst()._GetData();
} }
private DataType _GetData() {
return data;
}
private void LoadData() {
data = [Code to Load Data from JSON]
// Sanity Check
if( data != null ) {
Console.Log( $"{Data}" );
}
}
}The biggest problem with the code above is that it compiles and is logically wrong by exactly 1 character. That character isn’t even the wrong letter, just the wrong case for that letter. Worse, the program would start up, and then spend a bit of time not responding, and then crash without anything in the output panel in Godot. So I didn’t have any info to help me chase down the problem. If you’re stuck in a similar situation you can run Godot as a command line program from a CMD or terminal window, and for some reason that approach doesn’t eat the logs when it crashes.
Imagine the above code running for a moment. Let’s start with a singleton that has never been accessed so the inst variable is still set to null.
You attempt to get the data like this:
DataType coolData = Singleton.Data;The Data property calls GetInst() to get the only copy allowed and discovers there isn’t one yet so it makes one. This causes the data to be loaded from disk in the LoadData() method. Due to previous issues with JSON formatting the code has a sanity check that outputs the DataType object to the console. Except that is an attempt to get the data through the property, not the instance variable. To access this property, GetInst() is called and discovers there isn’t an instance yet because we are still in the constructor from our last attempt to make one. This then runs the constructor again, which loads the data again, which tries to output the contents of the data again, which accesses the data through the property which calls GetInst() which still doesn’t have anything to use, which tries to make one… and so on, forever. And just like that, an infinite loop that tries forever to get an instance of something while still making an instance of that same thing. It will crash when the call stack gets too large, but it will actually read the data from storage on EVERY nested attempt. That’s why the stack overflow doesn’t happen instantly.
As mentioned before groundhog day took over the previous paragraph, the only bug is that line in LoadData():
Console.Log( $"{Data}" );
// should be:
Console.Log( $"{data}" );And just like that, the infinite loop vanishes. Technically speaking it was infinite recursion, not an infinite loop, but thanks to a total lack of output inside Godot, I didn’t know that until later. Pro-tip to my developer friends out there: Pay attention to what you’re doing because you can easily end up with code that seems right and proves to be a pain to debug.
