Unity 2017 and null conditional operators

Is there any update on the support of null conditional operators and null coalescing operators in Unity 2017 with experimental .NET 4.6 support?

I am talking about the ?? and ?. operators. I am fully aware you should not use them for any Unity class but all posts about those lie way back in time and I would really hope unity will provide support for them.

Are they already supported? Will they ever be (are there current plans, have the plans changed, is it plain impossible because of the backing c++ objects?)

We have not made a final decision on this yet. This is on our radar and we will share the details once a decision has been made.

the problem is that a null Unity Object is not always null:

  • it is null if you assign null to it (or get it from some API that actually return null)
  • it is a ā€œfake nullā€ object reference if it’s a public field in the editor
  • it is an invalid (but not null) reference if it’s a destroyed object
  • [other cases I have not considered?]

UnityEngine.Object then overrides the == operator to make a ā€œfake nullā€ object to appear as it were null,
but the ?? and ?. operator are not overridable in c#, and they check for null in the strict sense (i.e. the reference is actually ReferenceEquals to null).
making them use the overridden == operator would be a breaking change in the language.

the only option would be to make the operator themselves overridable in a future version of c# (or a unity mod to the specs, but I hope they don’t).
right now there are overridable ā€œoperator trueā€ and ā€œoperator falseā€ that are used in short-circuiting && and || for custom types (they were used for DB interop if I remember right)
maybe a new ā€œoperator nullā€ could be added that modifies the ?? and ?. behaviour (it would still break code that relies on the difference between real and fake null, if there is any out there, but that can be changes to a direct object.ReferenceEquals call)

in my code I have an extension method as a workaround, like:

public static T RealNull<T>(this UnityEngine.Object obj) {
    return obj ? obj : null;
}

(using the implicit bool conversion)
then use it likevar finalObj = myObj.RealNull() ?? defaultObj;

3 Likes

Am I missing something. Should your extension method work as written? The compiler tells me for your extension method: ā€œCannot convert expression type UnityEngine.Objectā€ to type T.

Haven’t written extension methods myself so far.

no it was just an example written on the fly. it should take a T as parameter, constrained on UnityEngine.Object.
fixed version:

public static T RealNull<T>(this T obj)
    where T : UnityEngine.Object
{
    return obj ? obj : null;
}

(this time I compiled it)

ps: never copy/paste/execute code from the internet without understanding it :stuck_out_tongue:

1 Like

Haha, I didn’t. I wanted to see if it compiles and make some tests on it, especially for something that important as breaking code because of ?? and null checks on unity objects :smile:

I was aware that it requires the type constraint on UnityEngine.Object, but thought the static class would provide it (which is not possible as I know now) . As I said I have not written extension methods so far but used them and read the MSDN documentation about them.

Long story short: Thank you for providing it and that you took the time to write that detailed explanation! I don’t think I will use it, but I ALWAYS want to understand it, and test it, and see what it does :smile: Even if I maybe won’t use it to use ?? now, I learned a lot about it and extension methods!

Semantics of null conditional operators absolutely must not be changed just to correspond initial design flaws in Unity. Unity just made a huge mistake going against standard recommendations for implementing equality:
https://msdn.microsoft.com/en-us/library/336aedhh.aspx «x.Equals(null) returns false.»
https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/operator-overloads «The semantics of the operator need to be compatible with several other members, such as System.Object.Equals.»

Please just do not do even worse by hacking Ā«?.Ā» Elvis operator.

5 Likes

I’m inclined to agree with @Qbit86 here that taking the equality hack further to the elvis operators is just getting deeper into the rabbit hole. I would much prefer Unity to align with the C# design standards than to sacrifice the standard for a little easier syntax focussed at beginners.

2 Likes

See the discussion in the last thread about this.

To me, it comes down to changing the semantics, which gives this:

someObj?.Foo();

Keeping everything as-is, which gives this:

if(someObj != null) someObj.Foo();

Or ditching the overload, which gives this:

if(someObj != null && !someObj.isDestroyed) someObj.Foo();

//or alternatively:

someObj.Checked()?.Foo();

In the last instances, the majority of the text is dealing with the possibility of null. That’s garbage. The interesting part of the code that I need to read is SomeObj.Foo().

I’d love for all three to be options we can set. If it can be set per-assembly, the assembly defines from 2017.2 removes the issue of incompatibility with asset store packages and plugins.

If choice is out of the picture, I’d prefer having the semantics that’s easiest to read and matches Unity the best.

Been coding C# in Unity for a year now and I didn’t even know this custom == was a thing :frowning:
This issue is kind of horrifying… what’s the best practice here even? I’m extremely used to relying on null to indicate state.

Also, from here: Unity Blog

  • The custom ==operator is not thread safe, so you cannot compare objects off the main thread. (this one we could fix).

Was this ever fixed?

1 Like

You really shouldn’t be working with UnityEngine.Object objects (the ones the overridden == are used for) off the main thread. As far as I understand it, those objects all have a version living on the c++ side of the engine, and the two versions kinda have to be in sync. Unity assumes that they only change during a frame.

In my experience, you only really run into this when using interfaces, because that’s the instance where you’ll be working with a UnityEngine.Object in a context where it’s not types as a UntiyEngine.Object. If you don’t have a lot of interfaces floating around, it’s probably not an issue.

Well…crap.

(I’ve got LOTS of interfaces on account of my love for Pure DI as well as encapsulation/separation of concerns).

Here’s an extension method I use to work around it:

/// <summary>
/// Checks if an object either
/// - is null
/// or
/// - is a UnityEngine.Object that has been destroyed.
/// 
/// Unity overloads the == operator for UnityEngine.Object, and returns true for a == null both if a is null, or if
/// it doesn't exist in the c++ engine. This method is for checking for either of those being the case 
/// for objects that are not neccessarilly UnityEngine.Objects. This is usefull when you're using interfaces, since ==
/// is a static method, so if you check if a member of an interface == null, it will hit the default C# == check instead
/// of the overridden Unity check.
/// </summary>
/// <param name="obj">Object to check</param>
/// <returns>True if the object is null, or if it's a UnityEngine.Object that has been destroyed</returns>
public static bool IsNullOrUnityNull(this object obj) {
    if (obj == null) {
        return true;
    }

    if (obj is UnityEngine.Object) {
        if (((UnityEngine.Object) obj) == null) {
            return true;
        }
    }
    return false;
}

Thanks. I’m not sure if I’ll end up using that or not, because a lot of my classes have a requirement that they can never touch/know about the Unity API (hence my extensive use of interfaces). Those are (in the not too distant future) going to be chucked into a separate DLL with no references to Unity so this code would end up breaking when I do that >.<

We decided to take an approach where as much game logic as possible is put into standard C# classes instead of monobehaviors. We’re treating Unity like a front end layer, with the bulk of the games logic being considered a mid or back end layer, e.g. CharacterComponent has a Character, and when Unity events/interactions happen the component just calls into Character to tell it what to do, and is subscribed to events on Character to react to things that happen to Character that need to be handled in the Unity layer.

I’ll need to check and see if/how often we’ve got a monobehavior implementing one of those interfaces for those cases where one of our classes needs to interact with something that has to be a monobehavior. >.< But it sounds like I may well end up having to implement a crap ton of additional exception handling which would probably take less time than a full architectural overhaul (which I probably wouldn’t do anyways because I ā€œneedā€ DI).

1 Like

you can still put if (this == null) return; or if (!this) return; whenever a UnityEngine.Object is implementing an interface. or be careful about their lifetime

Agree, the less Unity in Unity game — the better. Ideally, no Unity at all, with all their broken, non-idiomatic APIs.

Just do not implement your interfaces by MonoBehaviours — use aggregation instead. Wrapper classes are ā€œnormalā€ in sense of checks via Elvis operator, and they provide Alive property, which performs ā€œnull checkā€ for referenced MonoBehaviour.

1 Like

If Unity overriding == really hurts performance I think it should be changed because performance is issue #1 with Unity, for me at least.

Is there a beginner’s tutorial that covers this stuff that I missed? :open_mouth:

Unity tutorials are mostly for ā€œnoviceā€ programmers, who doesn’t know that stuff like overriding operators exists… Read the forums, I guess.

Yeah, you’re telling me… anyway randomly finding ā€˜quirks’ on a forum and in unexplained notes on documentation (that people swear is to be ignored), naturally should make anyone a little nervous about what they don’t know. Don’t want to be an expert, but want to have enough of a sense of this stuff that I could know if I hit an issue with it or when to search for answers.