google / j2cl

Java to Closure JavaScript transpiler
Apache License 2.0
1.23k stars 144 forks source link

`$isInstance` support for native interfaces? #128

Closed realityforge closed 3 years ago

realityforge commented 3 years ago

I am trying to map Symbol type in a way that is J2CL/Closure Compiler compatible. As CC has an odd dichotomy between the @type {symbol} and the Symbol interface this requires a little bit of trickery. I was planning on splitting the representation of Symbol in java code into those two concepts.

The interface type representation is the obvious representation (See SymbolType) except that it returns/accepts values that are represented by the @type {symbol} which I am currently representing as an interface (See Symbol).

However this means that x instanceof Symbol no longer works. I was wondering does j2cl have any mechanism to override this check for a native type that is represented by an interface?

I tried something like the code snippet below but this is not accepted as the type is native and this method is not a @JsOverlay

@JsMethod
static boolean $isInstance( @Nullable final Object instance )
{
  return "symbol".equals( JsUtils.typeOf( instance ) );
}

Any other hints on how to move forward with this? I can convert the calling code to use typeOf but I am concerned that I will miss something somewhere and this will result in hard to track down bugs :/

gkdn commented 3 years ago

We don't support isInstance on interfaces; that is something we considered and even half implemented but there was some issues around it that I cannot remember at the moment.

Closure compiler dichotomy kind of makes sense. symbol is a primitive, Symbol is not; that's similar to difference between 'number' and 'Number' but very surprisingly to me one is not the boxed version of the other; unlike the case in number and string.

Is there any practical reason to separate the two and not only have a final Symbol class with private constructor?

realityforge commented 3 years ago

Originally I had just a single type of type Symbol and it works fine in GWT2.x but not so much in J2CL/CC as I could not get it to type check (i.e. the function definitions on Symbol type are of the "primitive" symbol type, not the Symbol interface type.) See https://github.com/google/closure-compiler/blob/master/externs/es3.js#L60-L65

Separating the two representations to match CC's world view was the easiest way to get closure to type check correctly.

I would prefer a single type as then I can probably generate it directly from IDL - the current files are the result of generation from IDL and then manual patching until I got it type checking. (i.e. Symbol and SymbolType are few of the hand managed files in https://github.com/akasha/akasha/tree/master/akasha/java/src/main/java/akasha/core).

gkdn commented 3 years ago

Does following not work:


@JsType( isNative = true, namespace = JsPackage.GLOBAL, name = "symbol" )
public final class Symbol {
  private Symbol() {}

  @JsProperty(namespace = JsPackage.GLOBAL, name = "Symbol.asyncIterator" )
  public static  Symbol asyncIterator;

  ...
}
realityforge commented 3 years ago

I expect that I could get the static property to work ... but Symbol would generate an $isInstance that would not work ... probably with a line something like instance instanceof symbol ... but if I provided my own implementation of $isInstance then that may work... I will try it in a bit

realityforge commented 3 years ago

Unfortunately that does not work either. You can not supply an $isInstance implementation for a native type and thus it will generate an overlay type with $isInstance where it does instance instanceof symbol which fails.

It looks like I will just have to be super careful when checking instances of Symbol which admittedly we only do in a handful of places. ;)

gkdn commented 3 years ago

Yes you will still have the problem of not being able to provide custom instanceof but at least you will have a simpler definition.

realityforge commented 3 years ago

A simpler definition that will not type check ;) ... because the generated overlay will have a line instance instanceof symbol where there is no such thing as symbol at runtime. The dual types in java to match the dual types in CC is not too onerous and seems to work across GWT/J2CL with the one limitation being that java's instanceof does not work.

Such is life - thanks for your time!