How can a static string be null?

I have a static string in my Player class, in case I want to init a player name from the menu.
Inside the start of Player class, I check if the initName length is bigger than 0(was set in the menu)
However, I am getting a null error exception if I did not set the initName in the menu.
I didn’t think a static string can be null? How does that work?

This is the code where I init the player name(It is inside the Start() of player class)
The line it gets the error is the one with the ‘if’

                if (initPlayerName.Length > 0)
                {
                    playerName = initPlayerName;
                    initPlayerName = "";
                }

This is how the initPlayerName is defined in the class.

public static string initPlayerName;

Only serialized fields in components and scriptable objects are automatically given a non-null value during Unity’s deserialization process.

Since static fields are not serialized by Unity, they will have their default value (null for class types) unless you assign something to them.

// you can use a field initializer to give a non-null initial value
public static string initPlayerName = "";
1 Like

Also note that even serialized fields in components will not be given non-null values by Unity, if they do not go through the deserialization process. So if you attach a component to a game object at runtime using AddComponent, make sure that all fields have been initialized properly.

public class MyComponent : MonoBehaviour
{
    public string serializedField;

    [ContextMenu]
    void TestAddComponent()
    {
        Debug.Log("Using AddComponent...");
        gameObject.AddComponent<MyComponent>();
    }

    [ContextMenu]
    void TestInstantiate()
    {
        Debug.Log("Using Instantiate...");
        Instantiate(this);
    }

    void Awake() => Debug.Log($"serializedField is null: {serializedField is null}");
}
2 Likes

Also, you can use string.IsNullOrEmpty(string) to check both conditions at once.

2 Likes

A variable being static has nothing to do what you can or can not assign to it. So where does the idea come from? Note that strings in C# are ALWAYS objects living on the heap. There are “interned” strings which are essentially statically loaded data. Such strings are literal strings in your code. So whenever you write "SomeString" in code, this would be an interned string instance. Though they are still loaded into memory. The point of interned strings is that the same literal will literally point to the same instance to save memory.

So like it was already mentioned, strings are reference types and reference types have null as a default value. So when you don’t assign anything to the variable, it will be null.

CodeRonnie just beat me to it. It’s common to use string.IsNullOrEmpty in cases where you’re not sure if the string is null or empty. Btw: The “empty string” is also an interned string instance.

2 Likes

Yeah it might be surprising that strings in particular can be null, since they are immutable and have value-type equality comparisons, which is more often only the case for value types - which indeed cannot ever be null.

Regardless, string is actually a class type in C#. It has just been given custom implementations for the == operator, bool Equals(object), int GetHashCode() etc. so it behaves like a value type in many ways, for convenience.

int struct1 = 123;
int struct2 = 123;
Debug.Log(struct1 == struct2); // true
struct1 = null; // not possible; does not compile

string class1 = "123";
string class2 = "123";
Debug.Log(class1 == class2); // true
class1 = null; // valid code; compiles
1 Like

I quickly made a small C# fiddle to show the difference between interned strings and how you could intern them “on-the-fly”. However this should never really be used at runtime. C# / .NET essentially uses a pool of interned strings. Dynamically created strings are not automatically interned as this would be extremely expensive to check if the string already exists in the intern pool. You can not remove strings from that pool, so you should not use that. As I said, all string literals are automatically in that pool.

Note that like @SisusCo mentioned, the string class has an overloaded == operator which actually checks if the two strings contain the same characters. However when stored in object variables, the normal reference comparison is used. Here, even the strings have the same content, they are not considered equal as they are two separate objects. When you use “string.Intern” you essentially do a lookup in the intern table and it returns the instance from the table. If the string is not in the table, it will add it to the table. If you want to know if a particular string exists in the intern table, use the static method string.IsInterned. It does the same as the Intern method, but when the string does not exist in the table, it returns null instead. So this method does not automatically add new intern strings to the pool.

You usually should not even think about the fact if strings are interned or not. Strings are objects but for the most part act like a nullable value type.

1 Like