Proposal: Java Interop, Functional Interfaces, Anonymous Implementation #2517
Replies: 11 comments
-
Isn't this something that should be limited to the interop layer and not "pollute" the language (assuming that can be reasonably done)? The way I understood it, the Java interop that's coming to .Net 5 is a port of what Xamarin.Android is already doing to .Net Core. I looked at a random Android API that uses a functional interface to see how it's presented in Xamarin: The method The second overload means you can use a lambda when calling that method, and no language changes are necessary. As for interfaces that have more than one method, maybe it would be enough to have some helper classes or methods? For example, the AsyncHttpClient example could be something like: int status = 0;
asyncHttpClient.PrepareGet("http://www.example.com/")
.Execute(new AsyncHandler<int>(
onStatusReceived: responseStatus =>
{
status = responseStatus.GetStatusCode();
return State.ABORT;
},
onHeadersReceived: headers => State.ABORT,
onBodyPartReceived: bodyPart => State.ABORT,
onCompleted: () => status,
onThrowable: t => { })); To me, this looks even better than the Java version. So, my question is: what are the reasons to solve these interop issues in the language, instead of doing it in the interop layer using existing C# constructs? |
Beta Was this translation helpful? Give feedback.
-
Would it be possible to implement an interface with only one non-default method, and multiple default methods using a lambda? |
Beta Was this translation helpful? Give feedback.
-
A lot of this does depend on how the Java interop layer works. Does Xamarin produce these overloads manually now or do they automate it? If so, how do they know what interfaces are "functional"? Java doesn't require that an interface do anything special to be treated as a functional interface other than only allowing a single required method. It could clue off of the As for the non-functional callback interfaces, sure, someone could write helper classes for each of them which follows a pattern of accepting a bunch of delegates. But that is kind of messy. These things aren't that uncommon, at least in the Java world. I also think that there's benefit to anonymous implementations outside of the Java callback use case, such as facilitating fluent APIs based on interfaces. These are patterns I find myself using in Java quite frequently and miss when I'm using C#.
This is possible (and common) in Java today. Most functional interfaces have defaulted helper methods: public interface Predicate<T> {
boolean test(T value);
default Predicate<T> negate() {
return value -> !this.test(value);
}
}
Predicate<Integer> isEven = value -> value % 2 == 0;
Predicate<Integer> isOdd = isEven.negate(); |
Beta Was this translation helpful? Give feedback.
-
Just to detail the code generation, it would be very similar to how C# emits display classes for closures today. The difference is primarily that the display class would also implement the functional interface and can be passed directly as an implementation of that interface: public interface IRunnable {
void Run();
}
public class C {
public void M(IRunnable runnable) {
runnable.Run();
}
public void M(string value) {
M(() => Console.WriteLine(value));
}
} the compiler would emit: public class C {
private sealed class UnspeakableDisplayClass : IRunnable {
public string value;
// doesn't really matter if the implementation is explicit or not
// the methods on a display class are internal, this is as close as I
// can get with legal C# syntax
void IRunnable.Run() {
Console.WriteLine(this.value);
}
}
public void M(IRunnable runnable) {
runnable.Run();
}
public void M(string value) {
var displayClass = new UnspeakableDisplayClass();
displayClass.s = value;
M(displayClass);
}
} |
Beta Was this translation helpful? Give feedback.
-
I don't like this syntax. It make the code more ambiguous that it was interface or function I would like C# could allow anonymous inheritance like java instead. I don't mind that we need to write it longer like public void M(string value) {
M(new IRunnable { Run() => Console.WriteLine(value); });
} It also more flexible that we could support any amount of interface's members. Not limited to just interface with one member |
Beta Was this translation helpful? Give feedback.
-
Could we have anything to control the generated interface to be a struct? Sometimes we might have a code like this public void DoSomething<T>(ref T obj) where T : struct,IRunnable
{
}
///////
DoSomething(ref new (struct,IRunnable) {
Run() => Console.WriteLine(value);
}); Also with generic constraint we could have multiple interface public void DoSomething<T>(T obj) where T : IRunnable,IDisposable
{
}
///////
DoSomething(new (IRunnable,IDisposable) {
Run() => Console.WriteLine(value);
Dispose() => value.Dispose();
}); Could we support this? |
Beta Was this translation helpful? Give feedback.
-
Could that last example (and the others to be honest) be just inferred: public void DoSomething<T>(T obj) where T : IRunnable,IDisposable
{
}
///////
DoSomething(new {
Run() => Console.WriteLine(value);
Dispose() => value.Dispose();
}); This would also get us closer to the Java syntax of just passing a lambda while still being explicit about creating a new object with method(s). |
Beta Was this translation helpful? Give feedback.
-
A humble suggestion. Perhaps you can have a look at the following project that offers in process Interop link between CoreCLR and the JVM instead of using an IPC (socket based) communication. This could have a relevant performance impact. Project: https://github.com/QuantApp/CoFlows-CE With kind regards |
Beta Was this translation helpful? Give feedback.
-
The anonymous interface implementation is a great Java feature that I have often missed in the C#/.NET land. I believe that this is a better solution than a single use classes that either pollute the namespace or need to be in some way hidden from view. |
Beta Was this translation helpful? Give feedback.
-
Just revisit this to ask if this is possible or not? public static ICollection<TResult> Select<T,TResult>(this ICollection<T> source,Func<T,TResult> func)
{
return new ICollection<TResult> {
int Count => source.Count;
IEnumerator<TResult> GetEnumerator()
{
foreach(var item in source)
yield return func(item); // yielding in anonymous
}
// throw for other implementation
};
} |
Beta Was this translation helpful? Give feedback.
-
With the announcement of .NET 5.0 and specifically the claim that it will include "Java interoperability will be available on all platforms" that is "two-way interop", I thought it was worth exploring some language proposals that may ease interop between the ecosystems. This may definitely be jumping the gun as it's hard to know what this Java interop may consist of or if these differences would be smoothed out by a form of marshaling.
I'll start with the features Java uses most often for the implementation of callbacks. Lacking an equivalent of delegates or function pointers Java generally managed callbacks through interfaces that define members for the callback functions.
Here's a real-world example of using anonymous classes for callbacks: https://github.com/AsyncHttpClient/async-http-client#using-custom-asynchandlers
Since Java 1.1 it has been very common for a consumer to implement the callback using an anonymous class which also acts like a closure. There are already proposals here to add such support for C# and I don't intend to repeat them other than to suggest that they would be very helpful for implementing callbacks from any Java (or Android) library.
Java 8 has also added lambdas to the language. These are also managed through interfaces but only permitted for interfaces that have exactly one required member.
What I propose is that C# follow suit in allowing lambda syntax to be used to anonymously implement an interface to be used as a callback:
Beta Was this translation helpful? Give feedback.
All reactions