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

Bug or Not?

Discussion in 'Scripting' started by claytoncurmi, Aug 1, 2014.

  1. claytoncurmi

    claytoncurmi

    Joined:
    Jul 6, 2010
    Posts:
    168
    Hi all,

    I have encountered a strange situation when using actions with optional parameters. The following code returns a totally random number rather than 10. When I use Action<int> rather than Action, the value is shown correctly. An alternative is to use method overloading to specify the default value for the optional parameter. Is this consider to be a bug or not?

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Test : MonoBehaviour
    5. {
    6.     void OnGUI()
    7.     {
    8.         if (GUILayout.Button ("Test Delegate"))
    9.         {
    10.             System.Action testMethod = new System.Action(TestMethod);
    11.             testMethod();
    12.         }
    13.     }
    14.    
    15.     private void TestMethod(int success = 10)
    16.     {
    17.         Debug.Log ("Success - " + success);
    18.     }
    19. }
     
  2. hammil

    hammil

    Joined:
    Jun 5, 2013
    Posts:
    56
    Hmm.. That's an interesting situation. I may be able to shed some light on this

    Default parameters don't have much of an effect on compiled code. All that happens is an attribute is applied to the parameter, saying what its default value is; the signature of the method remains void(int). If the parameter is omitted in code, the compiler will look for this attribute and add it in (in IL) for you. If you're forcing it to be void(), like you are now, then it will be called as such; the CLR doesn't know about the default parameter.

    Now, since the CLR is stack-based, when a method is called, the values on the stack are used by the method's code as the parameters. So what's happening here is it's popping an extra value from the stack, and using it as the parameter. However, that value isn't necessarily what it expects. It could be some random data, an object reference, or anything. That's where your random number will be coming from.

    The bug here is that the compiler doesn't give you an error when you try to force a void(int) method to be a void() method. You need to always use Action<int>, and manually put the default parameter in. Or just use an overload.

    Oh, and in addition, method references can usually be implicitly converted to their delegate types. So you just need to do
    Code (CSharp):
    1. Action<int> testMethod = TestMethod;