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

Discussion Inconsistent behaviors between editor, IL2CPP build and Mono build

Discussion in 'Code Editors & IDEs' started by FVS, Dec 27, 2022.

  1. FVS

    FVS

    Joined:
    Aug 10, 2015
    Posts:
    56
    Use the script below, and setup a simple scene with a button (to invoke Test() method) and a TextMeshProUGUI (to display the result).

    Click the button, Editor and a Mono build will show you string "TestClass", while a IL2CPP build will show you "ITestInterface.Foo".

    Please refrain from discussing whether my script is a "good practice" or not. And let's focus on the technical issue (I think we have here).

    Are the behaviors by the design of Unity or was it a bug?

    Thanks,

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using TMPro;
    4. using UnityEngine;
    5.  
    6. public class NewBehaviourScript : MonoBehaviour
    7. {
    8.     [SerializeField]
    9.     private TextMeshProUGUI text;
    10.  
    11.     public void Test()
    12.     {
    13.         ///
    14.         ITestInterface test = new TestClass();
    15.  
    16.         ///
    17.         text.text = test.Bar();
    18.     }
    19. }
    20.  
    21. public interface ITestInterface
    22. {
    23.     protected string Foo() { return "ITestInterface.Foo"; }
    24.  
    25.     public string Bar()
    26.     {
    27.         return Foo();
    28.     }
    29. }
    30.  
    31. public class TestBaseClass : ITestInterface
    32. {
    33.     protected virtual string Foo()
    34.     {
    35.         return "TestBaseClass";
    36.     }
    37. }
    38.  
    39. public class TestClass : TestBaseClass
    40. {
    41.     protected override string Foo()
    42.     {
    43.         return "TestClass";
    44.     }
    45. }
     
  2. DevDunk

    DevDunk

    Joined:
    Feb 13, 2020
    Posts:
    4,392
    If there is an inconsistency between mono and il2cpp make a bug report.

    First make sure you are on the latest bugfix version for your project
     
  3. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,194
    Yeah a default implementation of an interface should never be picked instead of the actual implementation of the interface. This is a bug in IL2CPP.

    You should make a bug report! @JoshPeterson will probably be interested in looking at it after vacation.
     
    DevDunk and FVS like this.
  4. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,503
    Interestingly, IL2CPP matches .NET 7 behaviour: https://dotnetfiddle.net/XWeWmV

    So this is probably a bug in Mono. A bug report would still be nice :).
     
    Anthiese likes this.
  5. Anthiese

    Anthiese

    Joined:
    Oct 13, 2013
    Posts:
    72
    There doesn't seem to be any violation of this here.
    As far as the posted code goes, it's a matter of not implementing the interface properly. If the default implementation of Foo were removed, you would get back an error that TestBaseClass doesn't implement ITestInterface.Foo. You would need to provide an explicit interface implementation. Introducing a protected member in TestBaseClass has semantics incompatible with implementing a protected interface member. Rider also shows a warning "Non-public method 'Foo' hides method with default implementation in interface ITestInterface"
    These rules apply at compile time for Unity 2022.2.2f1 (Editor), netcoreapp3.1 and net7.0. However, the Editor still decides to resolve ITestInterface.Foo to TestClass.Foo once the default implementation is provided. +1 for this being a Mono bug.
     
    Last edited: Jan 20, 2023
  6. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,771
    FVS likes this.
  7. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,194
    Could this be according to spec, somehow?

    I doubt it, since the method getting called is from an interface, and when you get a method from an interface you should be going to the actual implementation, but there might be some nuance in default interface methods calling each other that I'm not aware of.
     
  8. Anthiese

    Anthiese

    Joined:
    Oct 13, 2013
    Posts:
    72
    As I said, nothing you say applies in this scenario - there is no legal “actual implementation” in the code posted. The protected method in TestBaseClass isn’t supposed to be implementing the interface at all. Changing the interface method and declarations of the same name to public gives the behaviour you expect, as the TestBaseClass method would be implementing the interface method. Declaring a protected method in a class does not implement a protected interface method. You need an explicit interface implementation for that (ITestInterface.Foo(){}).
    https://learn.microsoft.com/en-us/d...verriding-non-public-interface-members-closed
     
    FVS likes this.
  9. FVS

    FVS

    Joined:
    Aug 10, 2015
    Posts:
    56
    Thanks for the source, the last time I checked they didn't decide yet, I'm glad it's settled now. Btw, to be clear, my issue here isn't about the decision, it's about consistency between editor, Mono and IL2CPP builds. My bug report is active in the issue tracker now (link in the comment above), and of course they will fix according the MS's doc.
     
    Anthiese likes this.