Skip to content

Java 8 Interface Binding #25

@jonpryor

Description

@jonpryor

Android N uses new Java 8 language features such as interface default methods and interface static methods, which are features that tools/generator hasn't had to deal with before.

The question: how should they be dealt with?

    // Java
    public interface HelloJava8 {
        public static final int VALUE = 42;
        public void a ();
        public default void defaultMethod() {
        }
        public static void staticMethod() {
        }
    }

There are at least three ways to do so:

  1. Ignore them.
  2. Expose them.
  3. Treat them specially.

Ignore them

Interface default methods don't need to be implemented, and static methods aren't implementable. The binding mechanism could thus simply ignore them entirely.

    // C#
    public interface IHelloJava8 {
        public void A ();
    }
    public static class HelloJava8 {
        public const int Value = 42;
    }

This isn't entirely desirable, because it also means default interface methods can't be called.

    IHelloJava8 value = ...
    value.DefaultMethod(); // error
    // No way to invoke HelloJava8.staticMethod()

On the plus side, implementors don't need to worry about them:

    public class WootJava8 : Java.Lang.Object, IHelloJava8 {
        public void A () {}
    }

Expose them

The "simple" version of "expose them" is do the simple thing: static methods are bound in the constant-containing static class, and default methods are bound as normal methods:

    // C#
    public interface IHelloJava8 {
        public void A ();
        public void DefaultMethod ();
    }
    public static partial class HelloJava8 {
        public const int Value = 42;
        public void StaticMethod ()
        {...}
    }

This allows calling both methods:

    IHelloJava8 value = ...
    value.DefaultMethod(); // works
    HelloJava8.StaticMethod(); // works

However, this means that C# subclasses need to implement all the default methods:

    public class WootJava8 : Java.Lang.Object, IHelloJava8 {
        public void A () {}
        public void DefaultMethod () {...}
    }

This might not seem bad in this example, but java.util.Collection contains five default methods (one inherited from Iterable).

This might be fine and acceptable, and we could help this scenario by providing access to the default method implementation:

    public static partial class HelloJava8 {
        public void InvokeDefaultMethod(IHelloJava8 self)
        {
            /* Non-virtual invocation of HelloJava8.defaultMethod() */
        }
    }

    public partial class WootJava8 {
        public void DefaultMethod ()
        {
            HelloJava8.InvokeDefaultMethod (this);
        }
    }

However, such "help" will require documentation and training to know about, complicating use.

Treat them specially

To a large extent, the concern is around C# implementations of the interface. It is seen that requiring that optional methods be implemented will complicate the C# experience. Perhaps we can fix this by splitting out the optional methods?

Then, we can use extension methods to invoke the default methods:

    // C#
    public interface IHelloJava8 {
        public void A ();
    }
    public static partial class HelloJava8 {
        public const int Value = 42;
        public void StaticMethod ()
        {...}

        public void DefaultMethod (this IHelloJava8 self)
        {
            // *Virtual* dispatch to invoke self.defaultMethod()
        }

        public interface IDefaultMethods {
            public void DefaultMethod ();
        }
    }

This allows calling both methods:

    IHelloJava8 value = ...
    value.DefaultMethod(); // works via extension method
    HelloJava8.StaticMethod(); // works

It also means that C# types don't need to implement the default methods:

    public partial class WootJava8 : Java.Lang.Object, IHelloJava8 {
        public void A () {}
    }

...but if the C# type does want to implement them, they can all be implemented by using the IDefaultMethods interface:

    public partial class WootJava8 : HelloJava8.IDefaultMethods {
        public void DefaultMethod () {}
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions