-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement multiple interfaces and Java intersection type support #1021
Comments
I remember we had some discussion in the past about using the We should make sure that whatever we come up with would also work with that API. Or maybe things would even be easier with that API if we can make it work with multiple implements clauses (and multiple mixins for the implementations - I vaguely remember something for generating mixins for implementations). |
For reference, FFIgen uses a builder pattern to implement multiple interfaces: final consumer = ProtocolConsumer.new1();
final protocolBuilder = ObjCProtocolBuilder();
MyProtocol.addToBuilder(protocolBuilder,
instanceMethod_withDouble_: (NSString s, double x) {
return 'ProtocolBuilder: $s: $x'.toNSString();
});
SecondaryProtocol.addToBuilder(protocolBuilder,
otherMethod_b_c_d_: (int a, int b, int c, int d) {
return a * b * c * d;
});
final protocolImpl = protocolBuilder.build(); Pros:
Cons:
I initially wanted to wait for macros to get a better syntax but we need this for #1022. So I want to implement a version of it. |
What problem are we trying to solve here? The code Foo.implement($FooImpl(...)); suggests that Then you want to be able to have one object implement two interfaces. The (In that case, could you perhaps create the individual handlers first and combine those? var fooProxy = Foo.implement(fooHandler);
var barProxy = Bar.implement(barHandler);
var fooBarProxy = combineImplements2<Foo, Bar>(fooProxy, barProxy); That way there What I would consider is:
Then, if you do (if (Foo & Bar).implements(invocationHandlerFrom({Foo: fooHandler, Bar: barHandler}) you get the effect of Foo.and<Bar>().implements(invocationHandlerFrom([handlerFor<Foo>(fooHandler, handlerFor<Bar>(barHandler)])) would work. (Strawman naming, can definitely be shorter.) And after that long derailed talk ... I also have no context on the FFIGen protocol builder, so I don't know what is being built. Using a builder pattern in general is usually a good idea, rather than having to create a value immediately from the first operation. More flexible. Also more verbose, but shorthands for the most common cases is usually enough to get around that. |
We currently can implement a single Java interface, and by implement I mean create a proxy object that redirects to Dart.
Here's a simple example to give you more context: abstract interface class $RunnableImpl {
factory $RunnableImpl({
required void Function() run,
}) = _$RunnableImpl;
void run();
}
class _$RunnableImpl implements $RunnableImpl {
_$RunnableImpl({
required void Function() run,
}) : _run = run;
final void Function() _run;
void run() {
return _run();
}
}
class Runnable extends JObject {
// Runnable has a factory named implement:
factory Runnable.implement(
$RunnableImpl $impl
) {
// ...
}
// ...
} Yes the value of the expression is used. For example The reason that the syntax is not simply
To make life somewhat easier we currently generate
I'm not a fan of this solution as it creates 3 objects in this case and makes object lifetimes a bit more complicated. If we're doing this, then it's better if |
Thanks, makes sense. So The problem here is to have a way to create a proxy for an intersection type, without having a Java class that implements both/all the types of the intersection. And preferably without having to create unnecessary intermediate objects. (Or at least not unnecessary Java objects?) Java can do this using the A builder is an option that doesn't stop at So, given something like: class JProxy {
external factory JProxy();
Object toObject();
} and Java types: class Foo extends JObject {
external factory Foo.implement($FooImpl handler);
external static void addToProxy(JProxy proxy, $FooImpl handler);
// ...
}
abstract interface class $FooImpl {
// ...
}
class Bar extends JObject {
external factory Bar.implement($FooImpl handler);
external static void addToProxy(JProxy proxy, $FooImpl handler);
// ...
}
abstract interface class $BarImpl {
// ...
} you can use it as: class FooBarHandler implements $FooImpl, $BarImpl {
// ...
}
void main() {
// Use one object or two different, your choice.
var myHandler = FooBarHandler();
var proxy = JProxy();
Foo.addToProxy(proxy, myHandler);
Bar.addToProxy(proxy, myHandler);
dynamic fooBar = proxy.toObject();
Foo foo = fooBar;
Bar bar = fooBar;
// Use it.
} Not paticularly ergonomic, but when Does make sense. And works with arbitrary number of interfaces. |
Makes sense, Thanks. It will also be quite similar to Liam's approach in ffigen so I'll go with this. |
Currently one can create an object which implements an interface
Foo
:What about the case where we want to implement both
Foo
andBar
, I propose adding a series ofimplementK
functions topackage:jni
.Probably subclassing
JObjType<T>
with a more specificJInterfaceType<T>
and using it for interface type classes. This will then be accepted byimplementK
methods, since we can't implement any class.And some classes to wrap multiple interfaces
The text was updated successfully, but these errors were encountered: