Static field initialization already is lazy

Sorry, but this is horrible.
You are demonstrating a pattern for global access (which should not be used in the first place), by wrapping an existing language feature for global access (statics) with the sole purpose of making it NO LONGER thread safe.

Your claim that statics are NOT lazy is just wrong. Static field initializers are by default lazy, only created when the field is first accessed. And they are protected against race conditions, preventing the instantiation of more than one object when multiple threads are accessing at the same time, which your completely pointless wrapping pattern is not.

What you are suggesting might be a good feature for other languages (if you insist on ignoring the fact that globals are evil), but this is a Unity tutorial. So please remove this.

What the hell?

Chill dude.

Are you referring to the first example (non-MonoBehaviour) of a Singleton, or the second example (MonoBehaviour) of a Singleton. In the case of the second (the one you’re most likely to use within Unity, this is the standard Unity Singleton pattern (arrangements of the if/else may vary but the result is the same, ensuring that there is only one Singleton).

For a non-MonoBehaviour Singleton, there are a number of setups that can be used, the simplest being

public class AmbientAudioPlayer
{
     public static AmbientAudioPlayer Instance = new AmbientAudioPlayer();
     private AmbientAudioPlayer() {} //Edited removed static keyword
}

The arrangement Sam uses, while not thread safe, sets us up for the MonoBehaviour version later in the lecture, and demonstrates what’s happening behind the scenes anyways. It’s easier for students who are unfamiliar with how Singletons work in the first place to understand. Thread safety isn’t much of an issue in Unity, as outside of DOTS/Jobs, nothing in the Assembly/C# domain is multi-threaded in the first place.

In terms of whether or not Singletons should be used in the first place, that’s a livelier debate. Personally, I avoid them whenever possible, but there are several instances where avoiding Singletons can be more cumbersome and complicated then ripping off the bandaid and using them. They are a tool, nothing more.

You’ll note that the next lecture “Better than a Singleton” is… in point of fact, another form of Singleton.

Sorry, this was not clear. I was exclusively referring to the first example.

That the first example sets us up for the second one is I think a big stretch.

My point remains that the reason given for the first pattern (static initialization would not be lazy) is just false.
For this reason the first example gets introduced as a pattern slightly better than just using the static.
But in fact the only difference to using a static is that it introduces a possible cause for bugs. Even if this is a very rare cause for bugs in a Unity context, when it is the only effect of the pattern, this makes it a really bad pattern. And this pattern should not be taught to beginners or anyone else.

Your sample code has some issues btw: it doesn’t compile. Static constructors can’t have access modification. If you are trying to limit initialization of the class to exactly one instance, it should be a non-static private constructor. In addition the Instance in your sample could be easily set to null from anywhere. I would make it a property (public static AmbientAudioPlayer Instance { get; } = new AmbientAudioPlayer() ; )

Sam never makes this statement, although it is somewhat implied. That being said, the C# language specification (here) says the following:

9.2.2 Static variables
A field declared with the static modifier is a static variable. A static variable comes into existence before execution of the static constructor (§14.12) for its containing type, and ceases to exist when the associated application domain ceases to exist.
The initial value of a static variable is the default value (§9.3) of the variable’s type.
For the purposes of definite-assignment checking, a static variable is considered initially assigned.

Which, at least to me, suggest that it is not in fact lazy. Except that the initial value of a static contained within a class will only be set when that class is first being accessed, not the variable.

I just looked at the code (again) and the lecture (again) and I don’t see any of these things.

  • There are no static constructors, so that point is moot
  • The instance is private, so it cannot be set to null from anywhere

As you quoted, “A static variable comes into existence before execution of the static constructor”. And this means directly before the execution of the static constructor.
Now if you look at the description of the static constructor:

The static constructor for a closed class executes at most once in a given application domain. The execution of a static constructor is triggered by the first of the following events to occur within an application domain:

  • An instance of the class is created.
  • Any of the static members of the class are referenced.

This means the static variable gets initialized the first time it (as the member of the static class) is referenced. So yes, it is indeed lazy.

The lesson strongly implies that statics are not lazy, naming lazy evaluation as the sole reason for using the pattern.

When I said “your sample code”, I was referring to Brian Trotters “simplest non-MonoBehaviour Singleton”, which does have a static constructor with a private accessor that does not compile. I’m sorry for the confusion, I should have quoted this part to make it clear.

Edit: Fixed formatting, thx Brian

This is true. You are correct that the static instance field will not be set until we access the class in any form.

As @Brian_Trotter mentioned, in the lecture the singleton pattern described is just a segway into the next part. The pattern described is not thread-safe and in most cases quite bad. As mentioned by Brian, this (thread-safety) is generally not an issue in Unity because nothing really runs on different threads. The lecture is also not teaching the pattern as much as describing its similarity to what is generally used in Unity. In the next lecture, Sam describes a way that does not use the pattern (iirc).

This is my bad, I thought you meant the code in the lecture. In Brian’s defense, though, he surely wrote that directly in the post (I do that all the time) and - with our growing dependency on help from IDEs - probably just overlooked the exact syntax.

Quite right, I accidentally put the static keyword in the constructor, which was an error. I’ve edited that sample.

The easiest method for this is to select the text you wish to quote in the post and click the “Quote” button that pops up near the quoted text. Anonymous quoting (without the header for the speaker) can be done with a > before each line, but this doesn’t work well (at all) for code blocks.

I’ll need to rewatch the lecture. While I’ve seen some other discussions on Singletons include Lazy evaluation as a condition of whether or not to use a Singleton, the most compelling reason to use a Singleton pattern is enforcement of the “One and Only One” principle. When using them with MonoBehaviours, the pattern doesn’t even qualify as lazy evaluation, as the instance field can easily be accessed by an outside class before it is assigned, depending on the order in which scripts are executed. It’s one of the things that can make a Singleton problematic in Unity, if you act on another classes Instance in any Awake method.

I’m still not entirely sure when you speak of a pattern we should never teach in the first place if you mean the sample implementation of the non Mono (which, once again, wouldn’t generally be used in Unity) or the Singleton itself. I think we’ve hashed out that the former is not the best example of a Singleton in C# outside of Unity. If it’s the latter, while I (and many) believe that Singletons should be avoided whenever possible, it is a commonly used design pattern in Unity. Ignoring it and pretending it doesn’t exist serves nobody. My preference would have been for the next lecture to be an example of how to avoid using a Singleton in the first place (the PersistentObjectPrefab/Spawner, while interesting, is still a Singleton, much like a Singleton is, in fact, just another form of global state).

I was exclusively talking about the first (non Mono) pattern. Even if the chances of it being used are smaller in a Unity context, it is still a bad way to implement Singletons/Global Access that should not be taught.

Yes, I was also not trying to discuss Singleton patterns or global access in general (just hinting mostly in brackets which side I’m on). This would be a discussion that has already filled hundreds of forum pages.
I was specifically talking about the implementation of the pattern shown at the beginning of this lecture. The idea to wrap the statics with lots of other code that has no benefit at all.

I think you’d find we’re in fairly close agreement on Singletons and global state in general. I use the Persistent Object Prefab from the next lecture, as it’s part of the backbone of the RPG course series, but seldom use the Singleton as it’s described in this lecture.

My bad habit is static events. When using the EventHandler model for the event, the calling object is embedded in the event’s Invoke.

Privacy & Terms