How to make compilator diferentiate function() :void vs function() :IEnumerator ( from C# call )

From what I read so far, it is impossible. But hey, impossible is nothing! :smile: hum…

Well, here’s the issue:

I have a Javascript Class static that let me access its Methods from C#. Let’s call this static class MyClass ( so innovative ).

Here’s what I have in it:

function MyCallbackWrapper( callback: function() : void )
{
     callback();
}

function MyCallbackWrapper( callback: function() : IEnumerator )
{
     StartCoroutine( callback() );
}

And let’s say I have a C# Script that does this:

      void Start ()
    {
        MyClass.Get().MyCallbackWrapper( TestVoid );
        //MyClass.Get().MyCallbackWrapper( TestIEnumerator );
    }

    public void TestVoid(  )
    {
        print ("MyVoid");
    }

    public IEnumerator TestIEnumerator( )
    {
        print ("MyIEnum");
        yield return 0;
    }

But the compilator throws: The call is ambiguous between the following methods or properties.

The two ambiguous methods are MyCallbackWrapper from the JS Class.

So now, why does it happens?
Long story short, in fact I first tried to do MyClass in C# but hitted a wall. In C# it looked like this:

      void MyCallbackWrapper( System.Action callback   )
    {
         callback();
    }

    void MyCallbackWrapper( System.Func<IEnumerator> callback   )
    {
        StartCoroutine( callback() );
    }

Which was throwing the same error : The call is ambiguous and stuff.

So, this error occurs in fact because the compilator cannot distingish the 2 methods, because the return type is not included in the process to get a unique method signature.
(c# - Compiler Ambiguous invocation error - anonymous method and method group with Func<> or Action - Stack Overflow)

Sooo! I thought that maybe UnityScript would handle things diferently. But not. I tried to use Function type instead, but the compilator wasn’t able to translate it for the C#.

Well, that was a lot to say, but here is what I’m searching now.

Option1: Despite the fact that I’ve searched for lots of “hacks” to make these 2 function non ambiguous, I didn’t find anything, but maybe I missed something. So if someone knows a trick, my eyes are wide open.

Option2: Dirtier but if this is the only thing possible I don’t mind : Use Reflection. But I’m at level extra noob on this one so I’ll need some help.

Option3 : It is possible to do it in Boo Edit: NOT WORKING

That was a dang long post, I you arrived at this line, I have to thank you for reading me. And if you have a solution, I’d probably make special wish for you next time I’ll see a shooting star.

Hmmm, well like the guy on the stackoverflow thread said, it’s a problem in the .NET spec, so I don’t think it will work in any Unity language including Boo since it will be treated the same. But, as for hacks, the guy in the thread did mention that lambdas, unlike Actions and Funcs, do include return type, so this compiles and gets routed correctly:

void Start ()
{
        MyClass.Get().MyCallbackWrapper(() => TestVoid());
        MyClass.Get().MyCallbackWrapper(() => TestIEnumerator());
}

You can keep the same code for the function definitions (the C# ones are fine), you just need to always call them with the argument wrapped in a lambda like that. Maybe that will work for you?

OK.

So this has to do with .Net delegates.

A delegate is an actual type, when you define a delegate what is actually created when it compiles is a class that stores a reference to the object the method is a member of and an IntPtr that points to the method. It also implements the method ‘Invoke’ which calls the method which is referenced by the IntPtr (integer pointers are pointers to the method in memory… think C++ function pointers in unmanaged code).

delegate void FooDelegate(bool value);

becomes:

class FooDelegate:System.MulticastDelegate
{
    // Constructor
    public FooDelegate(Object object,IntPtr method);

    // Method with same prototype as specified by the source code
    public virtual void Invoke(bool value);

    // Methods allowing the callback to be called asynchronously
    public virtual IAsyncResult BeginInvoke(Int32 value,AsyncCallback callback,Objectobject);

    public virtual void EndInvoke(IAsyncResult result);
}

When you define a function that accepts a delegate as it’s parameter. And you pass in the method itself, and not the delegate object, the compiler implicitly infers the delegate to use from the parameter of the method you’re calling. It then just injects the necessary delegate constructor for you.

public void CallDelegate(System.Action method)
{

}

public void Foo()
{

}

public void Bar()
{
    CallDelegate(this.Foo); //the type of the delegate is inferred because CallDelegate expects a System.Action
}

You’re not actually supposed to say

CallDelegate(this.Foo);

You’re supposed to say:

CallDelegate(new System.Action(this.Foo));

But, for ease, the compiler just allows you too say it short hand, because it can figure it out for itself at compile time. This is called “syntax sugar”.

The problem though is that when there is multiple overloads of the method accepting various types of delegates, the technique the compiler uses to infer the delegate type doesn’t work. See it’s not inferring the type based off the method you’re passing in, but based of the parameter of the method you’re calling.

You might be wondering why this is the technique used to infer the method. Why not instead use the shape of the method being passed in to determine the delegate to use. Well the problem here is that two delegates can be shaped identical, but not be the same type of delegate. It’s just the way that C# was designed in its early versions and remains a part of the architecture to this day.

delegate void Foo();
delegate void Bar();

Both are shaped the same, but you can’t say:

Foo a = new Foo(SomeMethodShapedLikeFoo);
Bar b = a as Foo; //NOPE!

Note that .Net 4 brought a new feature to bring delegates towards remedying these shortfalls. So far they’ve introduced variance and covariance… but there is still issues with OP’s problem directly. But eitherway, Unity uses an older version of Mono that only matches up to .Net 3.5 (and not even completely).

It works when you pass in a lambda or anonymous methods because lambdas are themselves delegate objects! The syntax sugar of an anonymous method/lambda method is that a delegate type is created and instantiated. The compiler therefore knows the shape of the delegate and can thusly match it to the overloaded method desired.

This means in the OP’s problem this can be all remedied by saying:

MyClass.Get().MyCallbackWrapper(new System.Action(TestVoid));
2 Likes

Note in this example code here. Though it’ll figure out which method to use. IT won’t operate the TestIEnumerator as a coroutine, because you’re lambda is being interpreted as a System.Action and is calling that version of the overload.

Thanks for your time to trying to figure it out guys. I missed one point, but the most “importanter” maybe, I don’t want the syntax ( yep, still ) to be something else than .MyCallbackWrapper( TestVoid ) or .MyCallbackWrapper( TestIEnumerator).

Because yep, I could have use lots of ways to resolve this god damn issue by passing lambda or casting things before being sent. But that sadly not what I want…

I’m actually searching to see what Boo could bring me with its Boo.Lang.ICallable.
( How to passing c# function as a param to UnityScript in unity? - Stack Overflow )
( Redirecting to Google Groups )

You’re going to have a problem if you don’t want to cast.

You’re going to have to. It’s a fundamental issue with .Net.

You’re only other option is to not use overloads and instead name the 2 methods 2 distinctly different names.

Something like:

MyCallbackWrapper
MyCoroutineCallbackWrapper

You had the same problem with the IEnumerator thing. Where you wanted to force a syntax you prefer in what is otherwise not possible in the language you’re using.

So you came up with this very hack method of doing it by using reflection to attempt to clone the IEnumerator, which as I pointed out in that thread is going to lead to some bugs down the line. And furthermore you couldn’t get to work for unityscript.

This is a related issue.

Here’s the thing.

Languages are defined by their syntax. If you break down the syntax in an attempt to force your own custom syntax, you’re technically not writing the language correctly.

And you said you’re doing this to make it easy for the users of your code.

But here’s the thing… if you allow them to write what is non-standard syntax. That’s actually harder. Because now they need to know your custom version of the syntax. So when bugs creep up, it becomes more difficult to see why it’s working, because under the hood in your source code you have some hack and slash method of accomplishing what you wanted (i.e. cloning the ienumerator with reflection).

Wouldn’t it be more reasonable to expect the users of your code to understand the syntax of the language they’re writing!?

I totally get your point and had a discussion with a friend IRL who, as a good coder, was telling me the same “expect the users of your code to understand the syntax of the language they’re writing”.

In fact, instead of him who learnt programming in school, I learnt it by myself. And it tooks me a lots of time to understand very simple notions. I have used things for months without even understanding what I was doing. But my code was working and I was fine with that. And from all this time, all I remember is constantly reading things I didn’t understand. I’m not great at RTFM thing. I learn by fail. Soo, all of this to say that yup, I agree with you for the global concept, but the reality is lots of people, especially on Unity, don’t know much about programming and they just DIY. And this audience doesn’t care about good practice or everything they just want their script to work. I’m not saying that this is a good thing to have people that doesn’t understand what they are doing, but I think that at least, it avoid the elit programming thing.

Now regarding this : “Languages are defined by their syntax. If you break down the syntax in an attempt to force your own custom syntax, you’re technically not writing the language correctly.”

I could agree too but actually a discussion to distinguish Action and Func with both generic parameters is hapenning for the next C# release, so it’s not that weird to trying to accomplish.

AAANND, last but not least, it’s more of a challenge, because I really love to find a way, even if it’s not a proper one!

I can feel you on that.

I too taught myself to code with a pile of books and web forums. I actually learned my core principles in Actionscript3 of all languages (a language known for breaking a lot of rules). Writing AS3, and going in knowing that it slap-dashed a lot of things introduced me to those rules and standards, which sparked my interest in learning them, and actually applying them to be a bit more rigid in what I was doing.

No, it works. I tested it. For a method “int Foo()”, “() => Foo()” is not an Action, it is a Func. Actions return void, Func returns int.

You’re right, I was reading that as:

MyClass.Get().MyCallbackWrapper(()=> {TestIEnumerator();});

Which would be an action.

Though it won’t be a Func, it’ll be a Func. Which I’m assuming was a typo.

Yes, I was just using int as an example because it was shorter to type and I’m incredibly lazy :wink: But yes, in the original example, it’s a Func.

But overall I agree with lordofduct, if you’re writing this as an API for some user, I would expect to just have two different methods: MyCallback and MyCallbackCoroutine. Overloading a method name can be convenient sometimes, but there’s no reason to tear your hair out trying to do it just because it looks pretty to have the two functions use the same name.

Update: It seems that this doesn’t work either in Boo… in fact the “method” object called “callable” act a bit like the “Function” object in UnityScript. So it works in UnityScript but not in C#.

Still digging…!

@Eric5h5 any tips? :]

I don’t think there will be any way to get it to work calling from C# no matter what language the other side is compiled in. C# is strongly-typed (at least until .NET 4, which you can’t use in Unity anyway) and always going to treat the call as one of its internal types, probably Action or Func, regardless of what it was originally in the DLL. And according to that thread, there’s no way to get this to work unless you use a lambda, and I’m almost positive that nothing in a DLL would ever get automatically translated as a lambda.

Can you give an example of where you would use this call where the programmer wouldn’t know the type? It seems like it would impossible to have any function “above” this function where they could pass in an argument that is either a void() or a coroutine, because they would run into the same problem with the ambiguous call, so I’m not really seeing the value in trying to get this working other than as a puzzle for its own sake. :wink:

Thank you for this answer! Well, the more I learn about generics because of this issue and the more I think the way you think.

The main problem is in fact that, when you use UnityScript you don’t have to specify the IEnumerator type to put a yield on its body.

So what is happenning is that people start coding in a untyped ( in fact void ) function, until farer in their project they need to add a yield in this function. SO. Without typing it, the method is now typed as IEnumerator. And worst of all, the method will now never be call because there is no StartCoroutine. Then the (beginner) user is lost and doesn’t have a clue of what’s happening and take ages to find out the whole thing.

So yep, as it has been said previously, it owes to the user to understand all of this, but since I know this is a very common error and that there is no warning log to help you on this, I keep hoping I could find a way.

I could think of a hack way to do it. This will work so that people writing Unityscript won’t have to concern themselves with anything. But it will mean that those who write C# will always have to explicitly declare the delegate type they expect to be passing in. Also you’ll have to write the implement code in C#.

Don’t have an overload, just one method. That method accepts a parameter of type ‘System.Delegate’. Then you use reflection to determine the return type of the Delegate, if it’s IEnumerator or IEnumerable, you start a coroutine. If it’s not, then you just treat it like an action.

public void CallbackWrapper(System.Delegate del)
{
    if(del.Method.ReturnType == typeof(IEnumerable))
    {
        StartCoroutine((del.DynamicInvoke() as IEnumerable).GetEnumerator());
    }
    else if(del.Method.ReturnType == typeof(IEnumerator))
    {
        StartCoroutine(del.DynamicInvoke() as IEnumerator);
    }
    else
    {
        del.DynamicInvoke();
    }
}

That’s the kind of hack I’m searching! This is maybe the best workaround so far. Regarding the fact that I’ll have to implement it in C#, it’s nothing but great for me. In fact all the asset is already written in C#. But since I found this “little” mega big issue, I was ok to re write the whole thing in Unityscript and even in Boo to make it work.

I didn’t try to call it from JS so far but I trust you regarding de feasabilty, now for the C# call, it’s still a bit complicated if the delagate can accept argument, like .CallbackWrapper( new System.Action(TestVoid), 2 ) or .CallbackWrapper( new System.Func<int, IEnumerator>(TestIenumerator), 1 ).

So I could make 2 different Method for C# ( accepting Action or Func) , because we could say that C# people are statisticaly more advanced in language comprehension about coroutines and stuff. And making one wrapper for the Unityscript people…

As I sad, so far the best solution.

I noticed that if you write the CallbackWrapper with its overloads in C#, UnityScript can figure it out, basically getting the same result as what I just posted.