-
Notifications
You must be signed in to change notification settings - Fork 8
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
Single impl interfaces? #2
Comments
Unlike earlier interface with single JSO case, you can have interfaces declare @JsOverlay methods that could do whatever you would normally do in the single JSO implementation. The resulting code should be similar to JSO case. But if you can give a more concrete example of what you are trying to achieve as the end result, I can try to provide better guidance. |
Given the option of rewriting the contents of the interfaces (and setting aside the downsides above), we can put
In both GWT2 and J2CL this fails with and without the
GWT2 without inherited
GWT2 with inherited
J2CL has the same errors with and without inherited
Omitting The goal though would be to not have to amend the original interfaces, but if that is supported (and I'm just doing it wrong), it would probably suffice. |
You can only have default/private methods to provide method implementation on interfaces; and that's what you need to mark with @JsOVerlay.
This is effectively similar to single jso impl in terms of where you could have one implementation in GWT and multiple implementations on server size. |
@niloc132, are you confusing SingleImpl with DualImpl? In GWT you are able to have Java interfaces implemented by a JSO and Java class, those are called DualImp interfaces. In such case the GWT compiler generates a trampoline to handle the dispatch to JavaScript. This is not a functionality that is part of jsinterop. SingleImpl scenario, on the other hand, is completely supported, that means that the interface is only implemented by JavaScript objects hence there will not exist any override of that method. You could achieve something similar to dual impl interfaces by using Say you have a JavaScript class @JsType(isNative = true, namespace = GLOBAL, name = "*")
interface DualImplInterface {
void m();
}
class JavaClass implements DualImplInterface {
public void m() { ... }
} HTH. |
@rluble you may be right that I'm thinking of something else. I do definitely want an overlay method, defined by the interface, and implemented in plain Java for the actual Java implementation (typically only on the server), and also separately implemented with one or more overlay methods for the JS impl of the method, since the underlying native type doesn't always make sense - in your example, Updating the example from my last post:
Up until now things work, until you have to provide a non-JS implementation of the interface method:
My question is how do you provide both a Java and JS implementation, where the underlying APIs are different. Assuming that both APIs are identical ( I'm sorry if this isn't very clear - it didn't seem to be covered in any of the docs I had found so far about JsInterop, and both answers seem tending in different directions. It does appear that I made a mistake about naming here (single vs dual), though the javadoc on I've been trying to work out the trampoline idea where overlays are needed - the closest I've gotten is something like three interfaces - one "actual" interface with default methods, and each default method tests if in JS or Java, and then casts |
I am still not sure if I fully understand your goal but in attempt to do my best, If you are simply looking for a way to do dual jso; the solution is still the same; you need to hand write the trampoline that was generated by GWT:
If this still doesn't answer your question; could you give a simple concrete example with your requirements as I asked earlier and how you solved in GWT2? |
One last point you have to think that If it is just to have a common API for Java and JavaScript then what @Goktug suggested is a way to go (just note that the interface there should be native |
I understand what an overlay method is (both the gwt2 and jsinterop variety) - and that you sorta-kinda-if-you-squint can override them, but only insofar as you first cast to the type that owns the method you are calling, its no longer dynamic dispatch, but just a static function that looks like an instance method, at least from the plain Java. My hope was that there was some clever way to end up with the type check "is this object a non-java object? okay, delegate to a specific static method, otherwise call the java method" - sort of the opposite of the instanceof in
To my knowledge this requires whole-world knowledge ("confirm there is exactly one implementation of the interface Foo so that Foo can be compiled with correct dispatch for it"), or that either Foo or Foo's JS impl is annotated in a clear way to reference the other. Likewise anything calling
|
Not sure what you mean that you can override them in J2CL. You can not; if there are cases where you can then that is a bug in the restriction checker. You could have server code that overrides them though, as long as it is not compiled with J2CL. That would definitely work on server only code, but not on shared code.
You could achieve that the following way. @JsType(isNative = true,...)
interface Foo {
interface JavaFoo extends Foo {
void barImpl();
}
@JsOverlay
default void bar() {
if (this instanceof JavaFoo) {
((JavaFoo) this).barImpl();
} else {
// code for the javascript case.
}
}
} You could also do more hacky things like checking for the presence of a particular property in your JavaScript object to decide how to resolve the dispatch. But it is intended that scenarios like this be resolved with user code. There is no clever way to universally distinguish them because J2CL blurs the lines between Java and JavaScript. E.g. there is no way to distinguish between a JavaScript array and Object[], Java class can extend JavaScript classes so they don't extend j.l.Object, etc.
jsinterop design is not only motivated by modular compilation but also by having a simple model that is easy to communicate. Even if there were an easy way to support this we would need a compelling reason to extend the spec. And I don't think there is a clean easy way to support it without extending the spec. J2CL aims to give a consistent view and seamless (Closure) JavaScript interoperation. Many GWT idioms need to be replaced for more JavaScript like idioms. Instead of a dual impl JSO, it is better to have a JavaScript interface implemented by the native object with a native JsType interface to expose it to Java code.
Yes. |
The main limitation here is inability to use the same method names in pure Java classes, so you need to come up with 2 contracts; Foo and FooJava interfaces where overlay calls to the Java specific one. I don't see any other natural way to solve this. GWT2 solution is quite magical and it is one of the pieces we were sure that we didn't want to carry over. Having 2 contracts is not ideal but something you can design an APT for to make it less error prone. If you need something like isJavaScriptObject, it could be more or less implemented as .constructor == Object.constructor but since you need a second interface for Java you can just check for instance of that. |
Well, we just run to each other with Roberto; but it looks like you got nearly same answer in two different wordings :) |
In GWT2 with JavaScriptObject it was possible to have exactly one subclass implement an interface - the compiler would detect this and where necessary devirtualize the calls and dispatch correctly to either plain java implementations or the single native implementation.
With JSO, there were two ways to implement these:
From the original design doc option 1 is still apparently possible in jsinterop-annotations assuming the interface itself can be modified to be marked as native ("A native
@JsType
can only extend/implement native@JsType
s."), but option 2 is not possible at all ("A native@JsType
class can only have ... Final non-native JsOverlay methods that do not override any other methods").In the context of GWT2 these limitations may not necessarily make sense, but with j2cl they clearly seem to, since the interface and implementation might be compiled separately, so generating the dispatch mechanism when the interface is transpiled would need to depend on knowing about the implementation.
Are there any suggested patterns to solve these sorts of issues? Ideas I've entertained and their downsides:
@JsType(isNative=true)
and to only have declared members which 100% match the eventual JS implementation - this is not always possible when the interface comes from some upstream source (org.w3c.dom
,org.json
are some such examples where overlays can bridge the gap and let code share an interface).The text was updated successfully, but these errors were encountered: