Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Is this a bug in the compiler?

Discussion in 'General Discussion' started by LEGEND383, Feb 27, 2015.

  1. LEGEND383

    LEGEND383

    Joined:
    Aug 1, 2012
    Posts:
    20
    When I have a function that has two overloads as below:

    Code (CSharp):
    1. void DoSomething(MyObject obj1, bool doOtherStuff = false)
    2. void DoSomething(MyObject obj1, MyObject obj2, bool doOtherStuff = false)
    and I try to call the second overload without the optional parameter like so:

    Code (CSharp):
    1. DoSomething(obj1, obj2)
    where both 'obj1' and 'obj2' are instances of 'MyObject', I get an error about the call being ambiguous between the two. This doesn't make much sense to me because, unless I'm missing something, it should be calling the second overload and assuming the optional parameter to have it's default value.

    Visual Studio doesn't flag it, so am I missing something or is it a bug?
     
  2. Trexug

    Trexug

    Joined:
    Dec 2, 2013
    Posts:
    88
    Qualified guess:

    If MyObject inherits from UnityEngine.Object (ie. ScriptableObject, MonoBehaviour or similar) then it can be implicitly cast to a bool. Check this link to see what I am talking about. So the method on line one could be called with obj1 and a boolean which is true or false depending on whether obj2 is null or not.

    If Visual Studio allows it and Unity does not, it is likely because Unity some Mono compiler and Visual Studio uses something else (Roslyn?). This suggests to me that this is not a problem in newer versions of .NET and it will probably be fixed in a newer version of Mono as well.

    Personally I dislike the implicit casting Unity3D seems so fond of. Object -> Bool and Vector3 -> Vector2 (and vice versa) has only caused me problems which were very difficult to find. I would prefer the compiler to tell me when I am unintentionally using the wrong types.
     
  3. LEGEND383

    LEGEND383

    Joined:
    Aug 1, 2012
    Posts:
    20
    Huh, wasn't aware of that implicit cast to bool. Don't know who decided that was a good idea when you can just check if it's null, but hey, the more you know. Thanks for the info :)
     
  4. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    The bool check is not entirely the same as a null check. From memory the bool check also returns false if the object has been destroyed this frame, but the engine hasn't yet cleaned it up. Actual destruction doesn't happen immediately. My memory is fuzzy on this though, I'd verify before taking any action.

    The Vector3-Vector2 on the other hand is annoying. By rights you should be able to implicitly cast from a Vector2 to a Vector3, as no information is lost. The other way should not work. In practical terms I get ambiguous errors every time I add a Vector2 + Vector3. The system would work if the casting was only one way.
     
  5. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    The bool cast also happens for initialized objects like rigid body. If you haven't attached on to your object, one is actually still there, just not in an initialized state and will return false.

    Also, if I were you I would avoid using a default value and avoid using just Object as your parameter type if possible.
     
  6. Trexug

    Trexug

    Joined:
    Dec 2, 2013
    Posts:
    88
    That is true, the documentation says that the bool check returns whether the object "exists". Existing seems to be defined as not being null and not having been destroyed in an earlier frame. I would like to add that comparing a Unity Object to null using == works the same way - it isn't a "regular" null check either.

    This:
    Code (csharp):
    1.  
    2. if (gameObject == null)
    3. {
    4.     Debug.Log("It's null");
    5. }
    6.  
    appears to be equivalent to this:
    Code (csharp):
    1.  
    2. if (!gameObject)
    3. {
    4.     Debug.Log("It's null");
    5. }
    6.  
    ILSpy reveals that both are implemented using Object.CompareBaseObjects