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:
- Ignore them.
- Expose them.
- 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 () {}
}