moonsharp-devs / moonsharp

An interpreter for the Lua language, written entirely in C# for the .NET, Mono, Xamarin and Unity3D platforms, including handy remote debugger facilities.
http://www.moonsharp.org
Other
1.4k stars 213 forks source link

Proxy operator overloads #183

Open Morphan1 opened 7 years ago

Morphan1 commented 7 years ago

Hello! I've been implementing this library into a project of mine recently, and it works amazingly. I did run into one issue, however.

As it currently stands, I have been unable to find a way of overloading operators for proxy objects. For example, when using a Vector3Proxy for a Vector3 object, this:

public static Vector3Proxy operator +(Vector3Proxy a, Vector3Proxy b)
{
    // Target returns the proxied Vector3 - it has its own overload already
    return a.Target + b.Target;
}

throws an error:

ScriptRuntimeException: cannot convert a userdata to a clr type Assets.Lua.Vector3Proxy

I was unable to figure out any combination of return type and parameters (such as returning Vector3 or one of the parameters being Vector3) that would allow this to work. Any help would be appreciated! Thanks for your time and an amazing project!

bplu4t2f commented 7 years ago

That was an interesting ride!

The issue is not exclusive to operator overloading.

It is also not possible to call a function which has TProxy as argument:

script.Globals["func"] = (Action<Proxy>)(x => {});

The processor finds the correct overload in either case (static method, or operator, or ClrCallback), but when it attempts to BuildArgumentList, then ScriptToClrConversions.DynValueToObjectOfType fails. The UserData contains a TTarget, but the desiredType for the conversion is TProxy. udDesc.IsTypeCompatible(desiredType, udObj) returns false for the proxy descriptor (since TTarget is not an instance of type TProxy).

See https://github.com/bplu4t2f/moonsharp/commit/85f6fcad62851d2850434fd4e08592def6d5cdbb

The commit above fixes this (without breaking any tests) in a MEGA BAD way. IMO the correct approach would be to change the signature of the IUserDataDescriptor.IsTypeCompatible method so that it is possible to put all the logic I added in the commit into the IUserDataDescriptor implementation. This implies changing the return type from bool to object so that the method is able to return a different object than the one that was passed in. Of course, the name IsTypeCompatible would make no sense anymore.

PS:

In the meantime, you can use

class Vector3Proxy
{
    public static Vector3 Multiply(Vector3 l, Vector3 r)
    {

and pass a UserData.CreateStatic<Vector3Proxy> to the script, or use an instance method on Vector3Proxy.

Morphan1 commented 7 years ago

@bplu4t2f I actually decided to apply your patch locally for now - it seems to work great! I'm no stranger to "BAD" fixes, so until a more official fix is applied, this works for me for now. Thanks! 😄