Fwd: jsinterop woes: Part 2: return Double[]

110 views
Skip to first unread message

Vassilis Virvilis

unread,
Jun 26, 2017, 4:31:31 AM6/26/17
to google-web-tool...@googlegroups.com
Originally posted in gwt-users.

The question here is the same with the previous one.

Is this considered a bug? Should I report it as an issue? and if so where?

 Thanks.


---------- Forwarded message ----------
From: Vassilis Virvilis <vas...@gmail.com>
Date: Fri, Feb 24, 2017 at 2:44 PM
Subject: jsinterop woes: Part 2: return Double[]
To: google-we...@googlegroups.com


Hi,

I am not sure if it is a bug but it kills my beautiful jsinterop mappings.

Let's say that I have a native js function (d3.extent) that returns an array of something. It may be dates it may be doubles..

This is mapped nicely with

    public static native <T, V> V[] extent(T[] data,
            AccessorFunction<T, V> accessor);

Where AccessorFunction is

    @JsFunction
    public static interface AccessorFunction<T, V> {
        public V get(T d);
    }

The above scheme works for Date and other objects but it fails with Double. If I specify another variant of d3.extent that returns double[] it works

Here is the javascript exception

Uncaught Error: java.lang.ClassCastException
    at java_lang_ClassCastException_ClassCastException__V.java_lang_Throwable_createError__Ljava_lang_String_2Ljava_lang_Object_2 [as package_private$java_lang$createError__Ljava_lang_String_2Ljava_lang_Object_2] (dashboard-0.js:7245)
    at java_lang_ClassCastException_ClassCastException__V.java_lang_Throwable_initializeBackingError__V [as private$java_lang_Throwable$initializeBackingError__V] (dashboard-0.js:7300)
    at java_lang_ClassCastException_ClassCastException__V.java_lang_Throwable_Throwable__V (dashboard-0.js:7133)
    at java_lang_ClassCastException_ClassCastException__V.java_lang_Exception_Exception__V (dashboard-0.js:7381)
    at java_lang_ClassCastException_ClassCastException__V.java_lang_RuntimeException_RuntimeException__V (dashboard-0.js:29760)
    at java_lang_ClassCastException_ClassCastException__V (dashboard-0.js:57310)
    at javaemul_internal_InternalPreconditions_checkCriticalType__ZV (dashboard-0.js:72171)
    at javaemul_internal_InternalPreconditions_checkType__ZV (dashboard-0.js:72378)
    at com_google_gwt_lang_Cast_castTo__Ljava_lang_Object_2Lcom_google_gwt_core_client_JavaScriptObject_2Ljava_lang_Object_2 (dashboard-0.js:647)

It goes here
function com_google_gwt_lang_Cast_castTo__Ljava_lang_Object_2Lcom_google_gwt_core_client_JavaScriptObject_2Ljava_lang_Object_2(src_0, dstId){
  com_google_gwt_lang_Cast_$clinit__V();
  javaemul_internal_InternalPreconditions_checkType__ZV(com_google_gwt_lang_Cast_jsEquals__Ljava_lang_Object_2Ljava_lang_Object_2Z(src_0, null) || com_google_gwt_lang_Cast_canCast__Ljava_lang_Object_2Lcom_google_gwt_core_client_JavaScriptObject_2Z(src_0, dstId));
  return src_0;
}

Arguments:
  • src_0:
    • evaluated: js array of numbers as it should be
  • dstId:
    • evaluated: 2396
and then it goes to

function com_google_gwt_lang_Cast_canCast__Ljava_lang_Object_2Lcom_google_gwt_core_client_JavaScriptObject_2Z(src_0, dstId){
  com_google_gwt_lang_Cast_$clinit__V();
  if (com_google_gwt_lang_Cast_instanceOfString__Ljava_lang_Object_2Z(src_0)) {
    return !!com_google_gwt_lang_Cast_stringCastMap[dstId];
  }
   else if (src_0.java_lang_Object_castableTypeMap) {
    return !!src_0.java_lang_Object_castableTypeMap[dstId];
  }
   else if (com_google_gwt_lang_Cast_instanceOfDouble__Ljava_lang_Object_2Z(src_0)) {
    return !!com_google_gwt_lang_Cast_doubleCastMap[dstId];
  }
   else if (com_google_gwt_lang_Cast_instanceOfBoolean__Ljava_lang_Object_2Z(src_0)) {
    return !!com_google_gwt_lang_Cast_booleanCastMap[dstId];
  }
  return false;
}

where it fails.

Would it be possible to handle transparently also Double[] (and possibly String[])? as double[]?

   Thank you for reading that far...

Vassilis







--
Vassilis Virvilis



--
Vassilis Virvilis

Roberto Lublinerman

unread,
Jun 26, 2017, 1:09:27 PM6/26/17
to google-web-tool...@googlegroups.com
The short answer is that this is also not a bug.

Java arrays are typed, JS arrays are not. So none of the examples you have will fully work. 

E.g. If you do array instanceof Date[] on an array built in JS filled with Dates it will fail.

A native array is best modeled as SomeNativeJsType[] where there are not expectations on the contents of the array from the Java perspective.

We would have loved to have a more seamless array JsInterop.



--
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-contributors+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit-contributors/CAKbOjEzUf3LAK90Gnq%2B8B5Yzq7akyZPC%3DJ9ch1DFieqoOCJJVA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Colin Alworth

unread,
Jun 26, 2017, 1:16:48 PM6/26/17
to google-web-tool...@googlegroups.com
The example isn't doing instanceof though, it is just making that the return type for the method (albeit through the use of generics). Does this suggest that we should stop using arrays to refer to raw JS data, or at least expect that generics may fail in interesting ways around them (and at runtime of all places)?

elemental2.Array is full of cases where [] or ... are used as arguments, though this includes generic arrays (as opposed to generics _of_ arrays). If I understand you correctly, valid Java code that is passed a String[] or Double[] (or for example Element[]) may fail in exciting ways if passed one of these 'arrays'.

In case those are correctly handled, and it is important only to tell JsInterop about an array of generics  instead of generic representing an array, perhaps Vassilis should have another AccessorFunction which handles arrays instead? (Actually maye need 3 more, <T, V[]>, <T[], V>, <T[], V[]>, so I don't think this is a serious suggestion).

Otherwise your email seems to suggest that we need a type in jsinterop.base for all JS arrays instead of our current situation of pretending that java arrays and js arrays are compatible.

--
  Colin Alworth

To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-co...@googlegroups.com.

Roberto Lublinerman

unread,
Jun 26, 2017, 1:33:03 PM6/26/17
to google-web-tool...@googlegroups.com
On Mon, Jun 26, 2017 at 10:16 AM, Colin Alworth <co...@colinalworth.com> wrote:
The example isn't doing instanceof though, it is just making that the return type for the method (albeit through the use of generics). Does this suggest that we should stop using arrays to refer to raw JS data, or at least expect that generics may fail in interesting ways around them (and at runtime of all places)?

It is the programmers responsibility to make sure JS methods that are called satisfy the Java contract they declare, same thing as in JSNI. If you use non native arrays in JsInterop members you should be getting "unusable-by-js" warnings. 

Also I forgot to mention that you can definitely return JS arrays as Object[] too.

Of course you can do tricks (as people used to in JSNI) if you know the edges in the semantics. E.g. returning a Date[] if you are sure there will be no casts. You also have to be aware that when you use generics there will be casts at the invocation sites.

If you have raw JS array you should model it with either a NativeJsType[] or an Object[].


elemental2.Array is full of cases where [] or ... are used as arguments, though this includes generic arrays (as opposed to generics _of_ arrays). If I understand you correctly, valid Java code that is passed a String[] or Double[] (or for example Element[]) may fail in exciting ways if passed one of these 'arrays'.

varargs is a different animal, JS varargs are always cast appropriately (there is always prelude on Java methods that implement a native method with JS varargs that takes care of this).

Yes valid Java code might fail for instance if there is a (instanceof String[] call, etc).
 

In case those are correctly handled, and it is important only to tell JsInterop about an array of generics  instead of generic representing an array, perhaps Vassilis should have another AccessorFunction which handles arrays instead? (Actually maye need 3 more, <T, V[]>, <T[], V>, <T[], V[]>, so I don't think this is a serious suggestion). 
Otherwise your email seems to suggest that we need a type in jsinterop.base for all JS arrays instead of our current situation of pretending that java arrays and js arrays are compatible.

You can always use Object[], and nothing will fail.
 
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsu...@googlegroups.com.


--
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-contributors+unsubscribe@googlegroups.com.

--
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-contributors+unsubscribe@googlegroups.com.

Ignacio Baca Moreno-Torres

unread,
Jun 26, 2017, 4:42:22 PM6/26/17
to google-web-tool...@googlegroups.com
Oh, the classic array problem! ;) https://github.com/gwtproject/gwt/issues/9318

IMO as you are wrapping a client lib, and this code is not going to be shared (used in JRE), so just use elemental2.core.Array. Probably JsArrayLike is enough as an argument but returning an Array it is easier to use.

I use native arrays extensively in DTO, but I stick to some limitations and it works pretty well. I only use primitive, Boolean, Double or JsType(native) arrays. And as I use it in DTOs if I want to do anything I always make defensive copies. In practice, this makes much sense because you almost everytime need to do some filter/mapping/peek with those arrays, so I just use Stream.of(array) do whatever I want (filter/map/...) and either use forEach/collect/toArray. So the resulting collection has type markers so it gets back to safety.

In general using native arrays with JS libs it's not a good idea for does problems. So try to avoid. You can always overload this method so you can pass a native array but returns a JsType Array. And anyways, returning a native array is not very friendly as you are probably expecting something mutable (add/remove) so the java native array is really not a good container here. In some weird cases, I have been using the manolo's hack ;) (https://github.com/manolo/gwt-api-generator/blob/master/lib/com/vaadin/polymer/Polymer.java#L522) to make it mutable as a Java List, but it is pretty hacky. 

To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-co...@googlegroups.com.


--
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.

--
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.

--
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/CAC7T7gkT6sJfPZOmf-owaNLXxHyKCBFvhwHbgCasgXqjyCoaYA%40mail.gmail.com.

Vassilis Virvilis

unread,
Jun 26, 2017, 6:02:56 PM6/26/17
to google-web-tool...@googlegroups.com
Hi and thanks for answering.

I also tend to believe this is not a bug - but - it is definitely in my wish list.

@Colin jsinterop is certainly kind of fragile but if you bang your head against it at the end you start understanding the errors. In most cases you can fix the error by making the java code or the jsinterop declaration __better__. This is a case that I had to uglify my bindings. So I don't believe that is fails in new, unique and interesting ways. It is rather consistent. It may be somewhat fragile and cryptic but it is consistent and I don't believe that you will have a problem with element[] (assuming element is a jsinterop native, and com.google.dom.dontremember.element), double[] or boolean[]. But you will be in world of hurt if you try to communicate Double[], Boolean[], String[].

@Roberto
Please note that I am not mixing stuff (java and js objects in the same array, or different kind of objects in the same array).

D3 is doing the correct thing here. If you pass an array of something, let's say T[] you can expect that you will be getting T and T[] out of D3 functions (can't really remember the specifics). What I am passing are pure js objects modeled with jsinterop, and they still count as js, not java. So I am expecting to get back what I feed in / declared at the start.

That part works.

I am putting Date[] --> I am getting back Date[] . Correct
I am putting double[] --> I am getting back double[] . Correct
I am putting Double[] --> I am getting back exception. Not so nice.

That basically means that I can't have a generic function that will work with all kind of GenericTypes because double is not an object in java. That means I have to special case the interface like this

      V get(T t); --> works great for JsObects as it should
      double getDouble(T t) --> ugly huh?

So what do I want: Double[] to be castable to double[] in the GWT js context (not in the java context). I don't know if this is possible but it is definitely desirable. (The same for String[] and Boolean[]) and a pony of course :-)

Thanks again.

Roberto Lublinerman

unread,
Jun 26, 2017, 6:42:10 PM6/26/17
to google-web-tool...@googlegroups.com

@Roberto
Please note that I am not mixing stuff (java and js objects in the same array, or different kind of objects in the same array).

D3 is doing the correct thing here. If you pass an array of something, let's say T[] you can expect that you will be getting T and T[] out of D3 functions (can't really remember the specifics). What I am passing are pure js objects modeled with jsinterop, and they still count as js, not java. So I am expecting to get back what I feed in / declared at the start.


D3 is a JS api, even if some function says it will return an array of T, it is a JavaScript array, so there is no (type) guarantee that the array is of T. So it is an array of things, all of them of type T. 

A java T[] has even stronger semantics, if you set an element it will check that it is the correct type. So the D3 array is like an Object[] that happens to be filled all with Ts.


So what do I want: Double[] to be castable to double[] in the GWT js context (not in the java context). I don't know if this is possible but it is definitely desirable. (The same for String[] and Boolean[]) and a pony of course :-)


Again here Double[] and double[] have very different semantics in Java. 

- you can cast Double[] to Object[] but not double[] to Object[]
- you can store nulls in Double[] but not in double[].

They are semantically different. I agree that in some circumstances it seems convenient to ignore those. But in general GWT follows Java semantics (with a few exceptions)
 
Thanks again.

--
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-contributors+unsubscribe@googlegroups.com.

Vassilis Virvilis

unread,
Jun 27, 2017, 4:06:16 AM6/27/17
to google-web-tool...@googlegroups.com
@Roberto,

Agreed in all points. double[] and Double[] is not the same thing in java although it may be possible to be the same in js.

So until java supports autoboxing and unboxing in arrays I can see your point.

    Vassilis

On Tue, Jun 27, 2017 at 1:41 AM, 'Roberto Lublinerman' via GWT Contributors <google-web-tool...@googlegroups.com> wrote:

@Roberto
Please note that I am not mixing stuff (java and js objects in the same array, or different kind of objects in the same array).

D3 is doing the correct thing here. If you pass an array of something, let's say T[] you can expect that you will be getting T and T[] out of D3 functions (can't really remember the specifics). What I am passing are pure js objects modeled with jsinterop, and they still count as js, not java. So I am expecting to get back what I feed in / declared at the start.


D3 is a JS api, even if some function says it will return an array of T, it is a JavaScript array, so there is no (type) guarantee that the array is of T. So it is an array of things, all of them of type T. 

A java T[] has even stronger semantics, if you set an element it will check that it is the correct type. So the D3 array is like an Object[] that happens to be filled all with Ts.


So what do I want: Double[] to be castable to double[] in the GWT js context (not in the java context). I don't know if this is possible but it is definitely desirable. (The same for String[] and Boolean[]) and a pony of course :-)


Again here Double[] and double[] have very different semantics in Java. 

- you can cast Double[] to Object[] but not double[] to Object[]
- you can store nulls in Double[] but not in double[].

They are semantically different. I agree that in some circumstances it seems convenient to ignore those. But in general GWT follows Java semantics (with a few exceptions)
 
Thanks again.

--
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-contributors+unsu...@googlegroups.com.

--
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-contributors+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Vassilis Virvilis
Reply all
Reply to author
Forward
0 new messages