Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Why does the keyword 'is' not work in this scenario

Discussion in 'Editor & General Support' started by nick091702, Sep 11, 2023.

  1. nick091702

    nick091702

    Joined:
    May 17, 2022
    Posts:
    1
    Hello, I am a relatively new developer in Unity and C# however I have been working with Java for a long time. When I started with C# I really liked the idea of the 'is' keyword because of its readability. I did some research and a lot of people argue that using the 'is' keyword is much better than using ==. Even my IDE (JetBrains Rider) suggested that I use 'is' instead of ==. The problem is when I use 'is' for this bit of code I get a null reference exception however when I use == I don't and I was just hoping someone could explain the reasoning behind that so I can try to understand. Here is the code line I am referring to:

    Code (CSharp):
    1. if (PlayerControl.Singleton is null) return;
    Also I feel it is worth mentioning that within the
    PlayerControl
    class there isn't any operator overloading or anything like that so I am not sure why 'is' gives an NRE but == doesn't. If you know why I would appreciate an explanation, thanks!
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,722
    The problem is that Unity overrides the
    ==
    operator to detect destroyed objects (obj: https://github.com/Unity-Technologi.../Scripting/UnityEngineObject.bindings.cs#L506

    However it is not possible to override the
    is
    operator in C# so using
    is
    will result in different behavior than using
    ==
    for that type of object. Namely
    obj == null
    will return true when
    obj
    has been destroyed with the Destroy function or unloaded as part of a scene unloading, but with
    is null
    it will return false even for destroyed objects.

    This is all assuming that your
    PlayerControl
    class derives from UnityEngine.Object, which it does if it's a MonoBehaviour or ScriptableObject.
     
    Last edited: Sep 11, 2023
    SisusCo likes this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    This is the problem with "doing research."

    I suggest instead that you just move forward and learn how Unity works, the standard "When in Unity, act like you're in Unity."

    Try this approach instead: ask yourself again and again "Can I ...?" with the tiniest things possible.

    Imphenzia: How Did I Learn To Make Games:



    Tutorials and example code are great, but keep this in mind to maximize your success and minimize your frustration:

    How to do tutorials properly, two (2) simple steps to success:

    Step 1. Follow the tutorial and do every single step of the tutorial 100% precisely the way it is shown. Even the slightest deviation (even a single character!) generally ends in disaster. That's how software engineering works. Every step must be taken, every single letter must be spelled, capitalized, punctuated and spaced (or not spaced) properly, literally NOTHING can be omitted or skipped.

    Fortunately this is the easiest part to get right: Be a robot. Don't make any mistakes.
    BE PERFECT IN EVERYTHING YOU DO HERE!!


    If you get any errors, learn how to read the error code and fix your error. Google is your friend here. Do NOT continue until you fix your error. Your error will probably be somewhere near the parenthesis numbers (line and character position) in the file. It is almost CERTAINLY your typo causing the error, so look again and fix it.

    Step 2. Go back and work through every part of the tutorial again, and this time explain it to your doggie. See how I am doing that in my avatar picture? If you have no dog, explain it to your house plant. If you are unable to explain any part of it, STOP. DO NOT PROCEED. Now go learn how that part works. Read the documentation on the functions involved. Go back to the tutorial and try to figure out WHY they did that. This is the part that takes a LOT of time when you are new. It might take days or weeks to work through a single 5-minute tutorial. Stick with it. You will learn.

    Step 2 is the part everybody seems to miss. Without Step 2 you are simply a code-typing monkey and outside of the specific tutorial you did, you will be completely lost. If you want to learn, you MUST do Step 2.

    Of course, all this presupposes no errors in the tutorial. For certain tutorial makers (like Unity, Brackeys, Imphenzia, Sebastian Lague) this is usually the case. For some other less-well-known content creators, this is less true. Read the comments on the video: did anyone have issues like you did? If there's an error, you will NEVER be the first guy to find it.

    Beyond that, Step 3, 4, 5 and 6 become easy because you already understand!

    Finally, when you have errors, don't post here... just go fix your errors! Here's how:

    Remember: NOBODY here memorizes error codes. That's not a thing. The error code is absolutely the least useful part of the error. It serves no purpose at all. Forget the error code. Put it out of your mind.

    The complete error message contains everything you need to know to fix the error yourself.

    The important parts of the error message are:

    - the description of the error itself (google this; you are NEVER the first one!)
    - the file it occurred in (critical!)
    - the line number and character position (the two numbers in parentheses)
    - also possibly useful is the stack trace (all the lines of text in the lower console window)

    Always start with the FIRST error in the console window, as sometimes that error causes or compounds some or all of the subsequent errors. Often the error will be immediately prior to the indicated line, so make sure to check there as well.

    Look in the documentation. Every API you attempt to use is probably documented somewhere. Are you using it correctly? Are you spelling it correctly?

    All of that information is in the actual error message and you must pay attention to it. Learn how to identify it instantly so you don't have to stop your progress and fiddle around with the forum.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    ALSO, if you're gonna do singletons, make sure you do them correctly. With Unity, your code is NOT the application. You are merely an honored guest whose code may or may not be run, so plan accordingly.

    These singleton approaches work extremely well in the Unity ecosystem, giving you tons of flexibility and explicit control over lifetimes of objects.

    ULTRA-simple static solution to a GameManager:

    https://forum.unity.com/threads/i-need-to-save-the-score-when-the-scene-resets.1168766/#post-7488068

    https://gist.github.com/kurtdekker/50faa0d78cd978375b2fe465d55b282b

    OR for a more-complex "lives as a MonoBehaviour or ScriptableObject" solution...

    Simple Singleton (UnitySingleton):

    Some super-simple Singleton examples to take and modify:

    Simple Unity3D Singleton (no predefined data):

    https://gist.github.com/kurtdekker/775bb97614047072f7004d6fb9ccce30

    Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:

    https://gist.github.com/kurtdekker/2f07be6f6a844cf82110fc42a774a625

    These are pure-code solutions, DO NOT put anything into any scene, just access it via .Instance

    Alternately you could start one up with a
    RuntimeInitializeOnLoad
    attribute.

    The above solutions can be modified to additively load a scene instead, BUT scenes do not load until end of frame, which means your static factory cannot return the instance that will be in the to-be-loaded scene. This is a minor limitation that is simple to work around.

    If it is a GameManager, when the game is over, make a function in that singleton that Destroys itself so the next time you access it you get a fresh one, something like:

    Code (csharp):
    1. public void DestroyThyself()
    2. {
    3.    Destroy(gameObject);
    4.    Instance = null;    // because destroy doesn't happen until end of frame
    5. }
    There are also lots of Youtube tutorials on the concepts involved in making a suitable GameManager, which obviously depends a lot on what your game might need.

    OR just make a custom ScriptableObject that has the shared fields you want for the duration of many scenes, and drag references to that one ScriptableObject instance into everything that needs it. It scales up to a certain point.

    And finally there's always just a simple "static locator" pattern you can use on MonoBehaviour-derived classes, just to give global access to them during their lifecycle.

    WARNING: this does NOT control their uniqueness.

    WARNING: this does NOT control their lifecycle.

    Code (csharp):
    1. public static MyClass Instance { get; private set; }
    2.  
    3. void OnEnable()
    4. {
    5.   Instance = this;
    6. }
    7. void OnDisable()
    8. {
    9.   Instance = null;     // keep everybody honest when we're not around
    10. }
    Anyone can get at it via
    MyClass.Instance.
    , but only while it exists.

    -----------------------

    Your code is not the application. Unity is the application. Your code is just a minor guest at the party:

    https://forum.unity.com/threads/res...-problem-when-using-ioc.1283879/#post-8140583
     
  5. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,114
    Also the null-conditional (
    ?.
    ) and null-coalescing (
    ??
    ) operators won't handle fake null Objects property. So you can get a MissingReferenceException from seemingly safe code like this:
    Code (CSharp):
    1. var transform = PlayerControl.Singleton?.transform;
    Also note that only some of Unity's own members like
    Component.transform
    or
    Component.GetComponent<T>()
    will ever throw a MissingReferenceException. So if you by accident call your own methods on Objects that have already been destroyed, it might not cause any errors at all, and could go totally unnoticed (for better and for worse).

    Oh, and also beware that
    if(someComponent is null)
    can return false, even if no value has ever been assigned to the someComponent field! This is because serialized fields can have a "fake null" value assigned to them in the Editor :confused:

    So yeah, do keep on using
    ==
    and
    !=
    whenever checking if any instances that derive from Object (components, scriptable objects, game objects) are null.
     
    PraetorBlue likes this.
  6. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,114
    There are a couple of reasons why many non-Unity C# devs say that using
    x is null
    over
    x == null
    is always better.

    I think the best one is that it can help the compiler to give better compile errors.

    Consider this code:
    Code (CSharp):
    1. MyClass x = null;
    2.  
    3. if(x == null)
    4. {
    5.     x.DoSomething();
    6. }
    This looks like an accidental bug, and probably the
    ==
    was intended to be
    !=
    instead. But since the
    ==
    operator can be overloaded, it could in theory be that the user really wanted this behaviour, so the compiler will allow it.

    Similarly, the compiler will allow you to compare a value type object against null with the
    ==
    operator, even though value type objects can't ever be null, and this is most likely completely unnecessary to do, and just an oversight.


    Probably the most common reason though - and one which I don't think holds water - is that people are paranoid about the
    ==
    operator being overridden in a class without their knowledge to always return
    true
    or something. For this reason they (erroneously) believe that using the is operator is always the safer option:
    Code (CSharp):
    1. if(x is not null) // <- Now I know for sure this contains an object - I'm safe!!
    2. {
    3.     x.DoSomething();
    4. }
    But what they have failed to consider is that actually using the
    is
    operator can be less safe, because the
    ==
    operator has more likely been overloaded for a good reason rather than just for S***s and giggles - such as is the case with destroyed Objects in Unity.


    Then there are some less important reasons, like some having the perception that
    == null
    is the old-fashioned way and
    is null
    is new and cool way to do it.
     
    Last edited: Sep 11, 2023
    CodeRonnie likes this.