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?)
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;
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.
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
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 Even if I maybe wonāt use it to use ?? now, I learned a lot about it and extension methods!
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.
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
This issue is kind of horrifying⦠whatās the best practice here even? Iām extremely used to relying on null to indicate state.
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.
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).
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.
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.