# Wednesday, 11 March 2009
« 100% Pure Java | Main | New Development Snapshot »
Defining Delegates in Java

I finally implemented support for defining delegates in Java. The functionality will be available in the next snapshot.

Here's how to do it:

import cli.System.AsyncCallback;
import cli.System.IAsyncResult;
import cli.System.MulticastDelegate;

public final class RunnableDelegate extends MulticastDelegate
{
    public RunnableDelegate(Method m) { }
    public native void Invoke();
    public native IAsyncResult BeginInvoke(AsyncCallback callback, Object obj);
    public native void EndInvoke(IAsyncResult res);
    public interface Method
    {
        void Invoke();
    }
}

This is the recommended pattern. There is a little flexibility, but there are a number of strict rules, if you violate any of these rules, the class will fail to load (or compile with ikvmc) with a java.lang.VerifyError.

Delegate rules:

  • Class must extend cli.System.MulticastDelegate.
  • Class must be final.
  • Class must have a single method named Invoke that is public, native, non-final and non-static.
  • Class must have a single public constructor taking an inner interface named Method and have an empty method body (actually it must call the base class default constructor using the canonical bytecode sequence).
  • Class may have BeginInvoke/EndInvoke methods, but if it has either one it must have both. The BeginInvoke and EndInvoke methods must have a singature that is implied by the signature of Invoke.
  • Class must have a public inner interface named Method with a single method named Invoke with a signature identical to the Invoke method in the class.
  • Class may not have any fields.
  • Class may not have any other native methods.
  • Class must be static if it is an inner class. (This isn't a real rule, it follows from the other rules.)

The delegate is usable from Java like other .NET delegates, but obviously it doesn't add much value there. The real value comes from being able to better interact with other .NET languages. For example, one cool trick is this:

public final class RunnableDelegate
  
 extends MulticastDelegate
    implements Runnable
{
    public RunnableDelegate(Method m) { }
    public native void Invoke();
    public interface Method
    {
        void Invoke();
    }
    public void run()
    {
        Invoke();
    }
}

Now you have a delegate that also implements java.lang.Runnable. Unfortunately, C# doesn't understand that delegates can implement interfaces, so we need a helper method:

package ikvm.runtime;

public final class Delegates
{
    public static Runnable toRunnable(RunnableDelegate delegate)
    {
        return delegate;
    }
}

Now you can do this in C#:

java.lang.Thread thread = new java.lang.Thread(
    ikvm.runtime.Delegates.toRunnable(delegate {
        Console.WriteLine("Hello World");
    }));
thread.start();

I've currently defined delegates for java.lang.Runnable and java.security.PrivilegedAction as inner classes of ikvm.runtime.Delegates. There are some other candidate interfaces in IKVM.OpenJDK.Core.dll, but I'll only add them if there is demand, so let me know.

Wednesday, 11 March 2009 06:44:02 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]