Null coalescing doesn't work with components

This doesn’t work:

Rigidbody rb = t.rigidbody ?? t.gameObject.AddComponent<Rigidbody>();
rb.mass = tMass;

It gives Missing Component Exception when you try to access rb.mass.

But this works fine.

Rigidbody rb = t.rigidbody;
if (!rb) rb = t.gameObject.AddComponent<Rigidbody>();
rb.mass = tMass;

Which seems strange to me. Anyone care to explain why?

I don’t have an explanation why it doesn’t work but I wanted to thank you for pointing me to that null-coalescing operator which I didn’t know before :smile:

I always use the conditional operator in such cases:

Rigidbody rb = t.rigidbody ? t.rigidbody : t.gameObject.AddComponent<Rigidbody>();
rb.mass = tMass;

Note sure, but it could be how the null coalescing operator works under the hood.

UnityEngine.Object instances have the Equals and GetHashCode functions overriden and will throw null when in fact they exist(after they are marked for destruction). Depending on how the null coalescing operator works (something I’ve not seen before, and looks pretty handy), it could be using a different equality comparison, or comparison to null than the special version used for Components. It’s possible that there is some under the hood trickery that is tricking that operator. You could try creating the necessary comparison functions for you components to see if it changes anything.

Your first sentence explains it I think. When you say “if (something)” I believe it is just syntatic sugar for if (something==null) when something cannot be cast to boolean and is a nullable type. So if Objects override Equals then they probably will return a null when compared with == even though they are not null according to the ?? operator, which must not use the classes overrides.

That does get the code all in one line, but it’s slightly slower than my method because you are calling GetComponent<> twice if the rigidbody already exists. I realize the difference is probably trivial in most cases unless you are accessing a lot of rigidbodies.

The null-coalesce operator is handy because you can chain together a whole bunch of things…

a = b ?? c ?? d ?? e ?? “f”;

I dunno, if I had to do a = b ?? c ?? d ?? e ?? “f”;
I think I would feel that I did something wrong in the design phase.

You can embed multiple ternary operators(even though it is damn near impossible to read):

int a = 5;
int b = a < 1 ? a < 2 ? a < 3 ? 4 : 5 : a < 6 ? 7 : 8 : 4;

But I place it in the same situation of I felt I did something wrong in implementation to need that sort of behaviour.

Missing Component Exception is a Unity Specific exception that does relate to the Equals Override, so it’s likely a ReferenceEquals(object, null); sort of comparison that cannot be overridden.

That’s probably true. I don’t think I’ve ever used more than two at a time. But it does have it’s uses!

I finally worked around this with a method extension for getting/adding a component. Usage:

MeshRenderer renderer = GetComponent<MeshRenderer>(true);
using UnityEngine;

public static class GameObjectExtensions
{
    public static T GetComponent<T>(this GameObject gameObject, bool add) where T : Component
    {
        var value = gameObject.GetComponent<T>();
        if (value == null && add)
            value = gameObject.AddComponent<T>();
        return value;
    }
 
    public static T GetComponent<T>(this Component component, bool add) where T : Component
    {
        return component.gameObject.GetComponent<T>(add);
    }
}