Adding @JsFunction to java.util.function JRE Emulation?

165 views
Skip to first unread message

David Becker

unread,
May 11, 2016, 7:15:46 PM5/11/16
to GWT Contributors
I think it would be good to add @JsFunction to all of the java.util.function interfaces in the JRE Emulation so that we can use standard function signatures with JsInterop.  

Would that work?  Any drawbacks?

If you think that's a good idea, I can submit a patch.

Thanks!

Colin Alworth

unread,
May 11, 2016, 7:22:12 PM5/11/16
to GWT Contributors
Unfortunately, you can't add the annotation to an interface with more than one method, even if those methods are default methods, at least as it is currently implemented. 

I can't remember the exact specifics around why this is the case, but believe it has to do with handling functions passed from js into java, and not being able to nicely handle instances that decide to override those other methods as well. 

You could nearly achieve this effect by just making a method reference to the "apply" or "test" method, and passing that as an actual JsFunction type. I don't right away see a problem with syntactic sugar doing this automatically, but am sure that someone will be able to enlighten us as to what confusing side effects this might have (or alternately confirm that this is a great idea, and point to where in the compiler the changes need to be made). 

--
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit-contributors/13df9bed-108f-4cdf-8c00-123f1186e461%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Goktug Gokdogan

unread,
May 11, 2016, 8:47:57 PM5/11/16
to google-web-toolkit-contributors
We cannot impose @JsFunction restrictions on standard library @FunctionInterfaces. You can see some of the limitations in the Javadoc.

@Colin: I didn't understand your solution. Feel free to propose something more concrete and we can discuss over that.

Colin Alworth

unread,
May 11, 2016, 8:51:28 PM5/11/16
to google-web-toolkit-contributors
No, its not a solution, so much as a "here is a workaround that might satisfy your specific case as you build your JsInterop-based lib so that it looks like it can use @FunctionalInterface types". I do not believe it to be a comprehensive way to provide the feature requested. At some point I'll try to write it out in more detail in case there is any actual merit to it (I'm all but sure that there isn't, or you would have thought of it already).

Ray Cromwell

unread,
May 11, 2016, 9:07:15 PM5/11/16
to google-web-toolkit-contributors
The issue is that @JsFunction implementors must "extend
java.lang.Object" as their parent. because standard library functions
are/canbe implemented on classes with complicated type hierarchies,
this would cause failures to compile.

This restriction comes about from the efficiency trick we use to
reparent a lambda to have the native JS Function object as it's
parent. We can't reparent objects whose immediate supertype isn't
java.lang.Object, but not doing this trick would make output more
bloated/slow, and wouldn't allow Java8 lambas to act like JS functions
(e.g. can call Function.bind/apply/etc on them) without some kind of
wrapping/unwrapping process, plus an additional level of hacks to make
sure referential integrity was preserved.
> https://groups.google.com/d/msgid/google-web-toolkit-contributors/CADcXZMwvRokmP5nq84jmE40Dmos3eMmPDH-V4RcCz-%2BjbubvxQ%40mail.gmail.com.

David Becker

unread,
May 11, 2016, 9:41:29 PM5/11/16
to GWT Contributors
Well bummer.  Thanks for the detailed info.  Perhaps someday it can check if they do directly extend Object or not and either take the shortcut or the long way...  I'm afraid that's way over my depth in the GWT code to attempt a patch though.
>>>> To view this discussion on the web visit
>>>> https://groups.google.com/d/msgid/google-web-toolkit-contributors/13df9bed-108f-4cdf-8c00-123f1186e461%40googlegroups.com.
>>>> For more options, visit https://groups.google.com/d/optout.
>>>
>>> --
>>> You received this message because you are subscribed to the Google Groups
>>> "GWT Contributors" group.
>>> To unsubscribe from this group and stop receiving emails from it, send an
>>>
>>> To view this discussion on the web visit
>>> https://groups.google.com/d/msgid/google-web-toolkit-contributors/CADcXZMzaxRmFrvZUkQMG0VQETyJo5TWmjtFqPsn3msrBBvvLGg%40mail.gmail.com.
>>>
>>>
>>> For more options, visit https://groups.google.com/d/optout.
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "GWT Contributors" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/google-web-toolkit-contributors/CAN%3DyUA0CktOO8rpggbAcfPyTPhP7bp3fOTZgxSZiWyGq09waBw%40mail.gmail.com.
>> For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to the Google Groups
> "GWT Contributors" group.
> To unsubscribe from this group and stop receiving emails from it, send an

Jens

unread,
May 17, 2016, 2:13:09 PM5/17/16
to GWT Contributors

The issue is that @JsFunction implementors must "extend
java.lang.Object" as their parent. because standard library functions
are/canbe implemented on classes with complicated type hierarchies,
this would cause failures to compile.

This restriction comes about from the efficiency trick we use to
reparent a lambda to have the native JS Function object as it's
parent. We can't reparent objects whose immediate supertype isn't
java.lang.Object, but not doing this trick would make output more
bloated/slow, and wouldn't allow Java8 lambas to act like JS functions
(e.g. can call Function.bind/apply/etc on them) without some kind of
wrapping/unwrapping process, plus an additional level of hacks to make
sure referential integrity was preserved.

Can you elaborate on it? I think its really annoying that every project must redefine callbacks, functions, consumers, whatever just because JRE has some default methods in their version and GWT can not handle it. IMHO convenience is the most important thing here.

For example wouldn't it be possible to redefine the way @JsFunction works so something like:

1.) @JsFunction marks a parameter to be a functional parameter
2.) The type of the parameter that is marked with @JsFunction must have exactly one @JsFunctionTarget in its class definition
3.) @JsFunctionTarget marks an abstract method in an interface or in an abstract class.


Then we would do something like

@JsType(native = true, ...)
class SomeAsyncClass {
 
void onSuccess(@JsFunction Consumer<String> onSuccess);
}


interface Consumer<T> {
 
@JsFunctionTarget
 
void accept(T value);


 
// other default methods
}



JavaScript:

var asyncClass = new SomeAsyncClass();
var someConsumer = // ...anything that has implemented Consumer<String>
asyncClass
.onSuccess(
 
function(value) {  // @JsFunction tells GWT to generate a "bridge" method using the parameters of @JsFunctionTarget and delegates to the Consumer<String> implementation
    someConsumer
.accept(value);
 
}
);


The above is probably not fully correct JS and maybe has some "this" problems but I think you get the idea. Marking parameters as @JsFunction would allow you to choose wether or not you want GWT to handle a Consumer as callback or as ordinary object, e.g. if you do not annotate a parameter of type Consumer with @JsFunction then it will be passed as normal object without any bridge methods that delegate to a @JsFunctionTarget method.

Wouldn't this be possible?

-- J.

David Becker

unread,
May 17, 2016, 2:21:08 PM5/17/16
to GWT Contributors
That would be — awesome.  Pretty please?  :)

Ray Cromwell

unread,
May 17, 2016, 3:00:52 PM5/17/16
to google-web-toolkit-contributors
Jens, the issue is not anything to do with ambiguity, it has to do
with the way we are able to treat an anonymous class as both a
function and an object, see Runtime.java makeLambdaFunction

/**
* Create a function that applies the specified samMethod on itself,
and whose __proto__ points to
* <code>instance</code>.
*/
public static native JavaScriptObject
makeLambdaFunction(JavaScriptObject samMethod,
JavaScriptObject instance) /*-{
var lambda = function() { return samMethod.apply(lambda, arguments); }

if (lambda.__proto__) {
lambda.__proto__ = instance;
} else {
for (var prop in instance) {
lambda[prop] = instance[prop];
}
}

return lambda;
}-*/;


What this does is take a Java class, and a reference to it's prototype
method, creating a new function, and seeing its prototype to be the
Class.


This lets you invoke a lambda as both lambda() or lambda.method() in
JS and Java code, it also means stuff like lambda.getClass(),
lambda.hashCode() etc work.
> --
> You received this message because you are subscribed to the Google Groups
> "GWT Contributors" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to google-web-toolkit-co...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/google-web-toolkit-contributors/db6a7e36-b288-4107-90f2-6b66b696779c%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages