You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Aug 27, 2026. It is now read-only.
Repository navigation
Commit 29f9707
Browse filesBrowse the repository at this point in the historyBrowse files
[generator] Support default interface methods. (#459)
Fixes: #25
Context: #341
Java 8 supports [interface default methods][0]:
public interface HelloJava8 {
public void a ();
public default int getFoo () {
return 8;
}
public default void setFoo (int newValue) {
throw new UnsupportedOperationException();
}
}
With C#8, C# also supports [default interface members][1].
Add a new `generator --lang-features=default-interface-methods` flag
which takes advantage of C#8 default interface members to bind Java 8
default interface methods:
// C# binding of HelloJava8
public partial interface IHelloJava8 : IJavaObject, IJavaPeerable {
static new readonly JniPeerMembers _members = new JniPeerMembers ("HelloJava8", typeof (IHelloJava8));
void A();
virtual unsafe int Foo {
[Regsiter ("getFoo", "()I", "…")]
get {
return _members.InstanceMethods.InvokeVirtualInt32Method ("getFoo.()I", this, null);
}
[Regsiter ("setFoo", "(I)V", "…")]
set {
JniArgumentValue* __args = stackalloc JniArgumentValue [1];
__args [0] = new JniArgumentValue (value);
return _members.InstanceMethods.InvokeVirtualVoidMethod ("setFoo.(I)V", this, __args);
}
}
}
C#8 Default Interface Members cannot be used with legacy
`generator --codegen-target=XamarinAndroid`, as they require the
`IJavaPeerable` infrastructure in order to work.
Connector Methods are emitted within the interface binding, and not
within the corresponding `*Invoker` type.
If a Java default interface method is "invalid", we just skip binding
the method instead of invalidating the entire interface, just as we
do with classes and non-`abstract` methods.
Finally, the default interface method implementation uses `virtual`
dispatch, *not* non-`virtual` dispatch, in order to support Java-side
versioning. For example, imagine `exampele.jar` v1:
// Java
public interface Fooable {
default void foo() {
System.out.println ("Fooable.foo");
}
}
public class Example implements Fooable {
}
In v1, `Example` does *not* contain an `Example.foo()` method, though
`foo()` can be invoked on it, because of `Fooable.foo()`:
Fooable value = new Example();
value.foo(); // Invokes Fooable.foo()
In v2, `Example` overrides `Fooable.foo`:
public class Example implements Fooable {
public void foo() {
System.out.println ("Example.foo");
}
}
If our binding used non-`virtual` dispatch for `IFooable.Foo()`, and
bound `example.jar` v1, then if we updated `example.jar` to v2
*without* producing a new binding -- and why should a new binding
be required? -- then we would continue invoking `Fooable.foo()` when
we *should* be invoking `Example.foo()`. Use of `virtual` dispatch
thus ensures we support Java-side versioning.
[0]: https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
[1]: https://github.com/dotnet/csharplang/blob/f7952cdddf85316a4beec493a0ecc14fcb3241c8/proposals/csharp-8.0/default-interface-methods.md
Console.Error.WriteLine(Report.Format(true,Report.ErrorInvalidArgument,"lang-features=default-interface-methods is not compatible with codegen-target=xamarinandroid."));
0 commit comments