Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

Elvis operator / Null-Coalescing operator

Discussion in 'Experimental Scripting Previews' started by jvlppm_pf, Sep 28, 2016.

  1. Ferazel

    Ferazel

    Joined:
    Apr 18, 2010
    Posts:
    517
    Yeah, I've been seeing the elvis operator pop up in Unity code too. I'd submit a bug to let the InputSystem team know they either need to refactor or suppress the warning if it is a false positive.
     
  2. pdinklag

    pdinklag

    Joined:
    Jan 24, 2017
    Posts:
    154
    @JoshPeterson @superpig @joncham
    It's 4 and a half years since this thread was started, are there any news here? Any plans? If not even the Unity devs can properly handle this anymore (see @Ferazel 's post), why is still nothing being done about this?

    Do the painful step and get rid of your C# hacks, the longer you keep waiting the worse the confusion will be going forward. You should easily be able to do as @Ferazel suggested and make it a Unity preference so old projects are still compatible.
     
  3. Knil

    Knil

    Joined:
    Nov 13, 2013
    Posts:
    66
    pdinklag likes this.
  4. HaraldNielsen

    HaraldNielsen

    Unity Technologies

    Joined:
    Jun 8, 2016
    Posts:
    139
    We are fully aware that this is far from ideal. We do not having concrete plans but we are talking alot about getting closer to normal C# patterns, where this is one of them.

    Also; https://forum.unity.com/threads/unity-future-net-development-status.1092205/#post-7034914
     
    phobos2077 and VolodymyrBS like this.
  5. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,336
    Eh, you should be very careful about that.

    Ending up with making Unity's code more cumbersome to write in order to be "more standard" isn't going to help people much.
     
  6. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    if you are allowed to influence future c# development, you can propose to add an overridable
    operator null
    . if a class defines it, it will be used for null coalescing and
    obj is null
    -style pattern matching.
     
  7. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    I somewhat disagree; I think it all depends on where the user is starting from. If you only learned C# through Unity and you have to make the change to more standard C# that can be hard, but I think the more common case is devs who already know standard C# and are trying to learn Unity, and standardization would make things much easier for them. This thread subject is an ideal example. For people who already know C#, they assume null means null and all the null operators should work the same. Only people who started with Unity would have this concept that null might also mean a game object that is in the process of being destroyed. and that you need to avoid using all the C# null operators to watch out for this case.
     
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,336
    And that misconception lasts for like a day.

    Also, again, changing the operator doesn't change how the other null operators work. So the instances where you could use eg. ? or ?? or ??= would still be the same.

    A decent compromise could be to leave the implicit bool cast as is, and then remove the == overload. I've always prefered to use == null, but the implicit cast is fine. That'd leave both options open. I don't think it's going to be worth the amount of work, though, there's far more interesting things the language team should be putting effort into (runtime upgrades, modern GC, up to date C# version, etc. etc.).

    The big change that should happen is for Unity to remove the bogus null objects inserted for missing references, as they prevent us from using ? even when we know that the object can't ever be destroyed, and incur a significant GC cost in edit play mode.
     
  9. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Seeing as this argument's been going on for like 10 years, I don't think most people figure out that Unity uses fake nulls on their first day. I'd guess most people figure it out only after quite a while of hair pulling and debugging and wondering what the hell is wrong, some googling, and eventually landing on this very thread. Especially since Unity doesn't mention most of the weird non-standard stuff they do in any of their documentation. If Unity can get rid of the fake nulls on empty references then I agree that'd be great, but I was under the impression that they can't, so they should fix what they can.
     
    pitchblende likes this.
  10. pdinklag

    pdinklag

    Joined:
    Jan 24, 2017
    Posts:
    154
    I've not really known C# much before getting into Unity, so I'm with the fake null since day one too and I'm used to it. However, I'm also very keen on using language features like the coalescing null or elvis. I allow things to be null here and there explicitly, and I want to be able to handle that case using the possibilities that the language offers me to handle it. And I am doing just that, only for things being UnityEngine.Object I can't, and this results in very inconsistent code and that's what's hair-pulling for me personally, also because I have to explain this to students every semester.

    It's a stupid hack, the behaviour of which could just as well be implemented using a static checker like IsNonNullAndAlive(x), this has the very same semantics as far as I'm aware of. If anybody wants an extension method for that, they can write it themselves in literally one line. If anybody wants the implicit bool conversion (which I make use of a lot), they can write themselves in literally one line. C# offers all these features.

    I honestly feel like there's way too many arguments going on here about it and way too little acting. The longer this stays in, the worse the arguments are going to get.
     
  11. IDK when did you read the manual last time, but they are everywhere... These are virtually on every single class / object page where it is relevant:

    https://docs.unity3d.com/ScriptReference/Object-operator_Object.html
    https://docs.unity3d.com/ScriptReference/Object-operator_eq.html
    https://docs.unity3d.com/ScriptReference/Object.html
    https://docs.unity3d.com/ScriptReference/MonoBehaviour.html

    Especially the
     
    HaraldNielsen and xoofx like this.
  12. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    973
    Just to add one thing to this thread, one thing that comes from people having learnt C# in Unity, where a destroyed object can be == null but not really, is that it can result in coding practices that retain references to the managed objects backing destroyed objects, hence keeping the managed side reachable for GC purposes. Take a memory profile on a random project and see how many destroyed objects are reachable from code all over the place. Separating what null means and what a destroyed object means makes the difference quite a lot more obvious to the uninitiated.
     
  13. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    An easy solution for getting the (??) and (.?) operators to work would just be modifying the code or IL at or after comile-time to use the long-hand version of writing the same thing when the object is known at compile-time to be a UnityEngine.Object.
    • Shorthand: foo?.bar
    • Longhand: foo != null ? foo.bar : null

    The fact these two statements can possibly not be functionally identical is simply bizarre to me.
    (Same goes with foreach vs. for in simple cases like lists or arrays, or LINQ vs. manually enumeration, for that matter.)
     
  14. pdinklag

    pdinklag

    Joined:
    Jan 24, 2017
    Posts:
    154
  15. Gotmachine

    Gotmachine

    Joined:
    Sep 26, 2019
    Posts:
    37
    Aside from the whole discussion about changing current API behavior, my main gripe with this whole thing is that 99% of the practical problem could be solved by introducing a few additional methods or properties to UnityEngine.Object.

    I'm using these few extension methods since quite a while :

    Check if the underlying C++ object is destroyed/not initialized :
    bool IsDestroyed(UnityEngine.Object unityObject)

    Check if the C# object is null (ie, performs a "ReferenceEquals(ref, null)") :
    bool IsNull(UnityEngine.Object unityObject)

    Combination of both, equivalent as doing "ref == null", but a lot faster :
    bool IsNullOrDestroyed(UnityEngine.Object unityObject)

    This solve the main issue, which is clarifying the code intent and behavior instead of having to rely on subtle behavioral differences between the methods that implement the "destroyed is null" concept ("==", "!=" and "Equals()") and those that don't ("is null", "ReferenceEquals()").

    Also, the Unity overloaded null checks have a quite significant performance overhead compared to a regular null check, the linked implementation solves that.

    As for the ability to use "?." and "??", this is solved by a fourth extension method :
    T DestroyedAsNull<T>(this T unityObject) where T : UnityEngine.Object

    Example usage :
    Code (CSharp):
    1. MyMonoBehaviour unityObject = gameObject.AddComponent<MyMonoBehaviour>();
    2. unityObject.myField = 1;
    3.  
    4. int i1 = unityObject.DestroyedAsNull()?.myField ?? 2; // 1
    5. MyMonoBehaviour ref1 = unityObject.DestroyedAsNull() ?? null // unityObject
    6.  
    7. DestroyImmediate(unityObject);
    8.  
    9. int i2 = unityObject?.myField ?? 2; // 1
    10. int i3 = unityObject.DestroyedAsNull()?.myField ?? 2; // 2
    11.  
    12. MyMonoBehaviour ref2 = unityObject ?? null // unityObject
    13. MyMonoBehaviour ref3 = unityObject.DestroyedAsNull() ?? null // null
    Why after all this time these methods (or something equivalent) hasn't been included in the API is beyond me.