Search Unity

Fun with null

Discussion in 'Scripting' started by JanSietsma, Aug 20, 2012.

  1. JanSietsma

    JanSietsma

    Joined:
    Nov 16, 2010
    Posts:
    31
    Here's a null gotcha I just got stung by, I hope this helps someone else!

    Code (csharp):
    1.  
    2. Object o = new Object();
    3. print( o );  // "null"
    4. print( o == null ); // True
    5. print( ReferenceEquals( o, null ) ); // False
    6. print( (System.Object)o == null ); // False
    7.  
    8. Transform t = transform.Find( "DoesntExist" );
    9. print( t ); // "null"
    10. print( t == null ); // True
    11. print( ReferenceEquals( t, null ) ); // False
    12. print( (System.Object)t == null ); // False
    So UnityEngine.Object overrides override ToString and Equals to try to pretend to be null when it isn't. This makes for some pretty confusing debugging and unexpected behaviour in functions like:
    Code (csharp):
    1.  
    2. void CheckNotNull( object o ) {
    3.   if( o==null ) throw new Exception("barf");
    4. }
    5.  
    Personally, I think returning "null" from ToString() and returning true to equality with null is just asking for trouble. Now I've just got to make my sanity checking classes behave sanely :).
     
  2. JanSietsma

    JanSietsma

    Joined:
    Nov 16, 2010
    Posts:
    31
    So here are ways you should and should not check any Unity object for null.

    Of course you can simply use obj==null if the reference hasn't been passed into any generic functions or it hasn't been cast to a non-unity type.

    Doesn't work, uses System.Object.Equals()
    Code (csharp):
    1.  
    2. public static bool IsNull( object obj )
    3. {
    4.     return obj == null;
    5. }
    6.  
    Surprisingly this doesn't work either
    Code (csharp):
    1.  
    2. public static bool IsNull<T>( T obj )
    3. {
    4.     return obj == null;
    5. }
    6.  
    This does work, but adds a dependency to Unity. Can't use it for non Unity objects.
    Code (csharp):
    1.  
    2. public static bool IsNull<T>( T obj ) where T : UnityEngine.Object
    3. {
    4.     return obj == null;
    5. }
    6.  
    Amusingly this works, but obviously not for objects that are actually null.
    Code (csharp):
    1.  
    2. public static bool IsNull<T>( T obj )
    3. {
    4.     return obj.Equals(null);
    5. }
    6.  
    Almost equally (no pun) amusing is that this verbose line is the correct answer.
    This is the only way I know of checking whether a reference to a non-unity object or generic type is null or is a Unity object is pretending to be null.
    Code (csharp):
    1.  
    2. public static bool IsNull<T>( T obj )
    3. {
    4.     return EqualityComparer<T>.Default.Equals(obj,default(T));
    5. }
    6.  
    My sanity checking library is now sane again.
     
  3. Errorsatz

    Errorsatz

    Joined:
    Aug 8, 2012
    Posts:
    555
    That's interesting; glad I saw this before I ran into the issue, that would have been some confusing debugging.
     
  4. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,981
    Since we have already crosslinked this question to this thread here i link back and post a working null check for any kind of reference in a unity application.

    Code (csharp):
    1.     public static bool IsNull(System.Object aObj)
    2.     {
    3.         return aObj == null || aObj.Equals(null);
    4.     }
    The idea is simple, any "normal" null-reference will be handled by the first condition. Unity's fake-null-objects aren't actually null so the System.Object == operator returns false. In this case we additionally check the Equals function which is an instance function an will return true.
     
    aka3eka likes this.
  5. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,926
    marsonmao likes this.
  6. LateBindingLover

    LateBindingLover

    Joined:
    Sep 22, 2014
    Posts:
    2
    Old thread but one of the first problems I ran into using Unityscript. I specifically wanted to compare to null using pragma strict. My solution was kindergarten quality but it worked:

    declare an "empty variable" to compare:
    Code (JavaScript):
    1. #pragma strict
    2.  
    3. public var myGameObj: GameObject;
    4. private var emptyGO: GameObject;
    5.  
    6. start(){
    7.  
    8. if (myGameObj != EmptyGO){
    9.  
    10. //do something
    11.  
    12. }
    13. else{
    14.  
    15. //cry foul
    16.  
    17. }
    18.  
    19. }[code]
     
  7. Eluem

    Eluem

    Joined:
    Apr 13, 2013
    Posts:
    57
    I feel like I'm going mad. Does unity simply PRETEND that an object is null when it's actually still instantiated? In the code below I have an example where I am able to get a value out of a property from an object that is supposed to be null. Any advice?

    Code (CSharp):
    1.         if(myGameObj == null)
    2.         {
    3.             //Special null case
    4.  
    5.             Debug.Log(myGameObj.MaxHealth); //prints out 100 somehow...
    6.             Debug.Log(myGameObj); //prints null
    7.             Debug.Log(myGameObj.name); //Gives a MissingReferenceException error
    8.         }
    9.         else
    10.         {
    11.                 //Do stuff with game object
    12.         }
     
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,332
    The best explanation is in this blog post. The answer to the question the blog post asked seems to have been "yes, at least for now".

    From the last time somebody mentioned this:

     
    JanSietsma and Eluem like this.
  9. Xander-21RUS

    Xander-21RUS

    Joined:
    Sep 9, 2016
    Posts:
    1
    Upper Posts does not work for my case. i solved it in this way;

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3.     public class NullSolving:MonoBehaviour {
    4.  
    5.         private byte FieldForTestAccess=0;    //or any field ,not especially fo test.
    6.  
    7.         void Start(){}
    8.         void Update(){}
    9.  
    10.         public static bool isNull(NullSolving nullSolving){
    11.  
    12.             try{
    13.                 byte CheckAccess= nullSolving.FieldForTestAccess ; // if object is null thrown Exeption
    14.                 return false;
    15.             }catch {
    16.                 return true;
    17.             }
    18.  
    19.         }
    20.     }
     
  10. kru

    kru

    Joined:
    Jan 19, 2013
    Posts:
    452
    That is a pretty slow way of checking for null. When an exception is thrown, the entire stack is unwound, which is a very, very slow process. It's brutal on mobiles and consoles.

    You should just be able to do
    Code (csharp):
    1. bool IsReallyNull(System.Object obj) { return System.Object.ReferenceEquals(obj, null); }
    and get the same results with a faster speed.
     
    matheus_inmotionvr likes this.