google / j2cl

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

Error when subtracting long #150

Closed rbsdc closed 2 years ago

rbsdc commented 2 years ago

The following works when transpiled to JavaScript:

public static int testFunctionInt(int size, int start, int bufferLength) {
    return Math.min(bufferLength, size - start);
}

The following, however, does not work:

public static int testFunctionLong(long size, long start, int bufferLength) {
    return (int) Math.min(bufferLength, size - start);
}

Here, the following error is thrown:

Uncaught TypeError: module$exports$vmbootstrap$LongUtils$impl.m_toNativeLong__java_lang_Object(...).subtract is not a function

The error can be traced back to the following code:

module$exports$vmbootstrap$LongUtils$impl.minus = function (a, b) {
  return module$exports$vmbootstrap$LongUtils$impl.m_toNativeLong__java_lang_Object(a).subtract(b)
};

Here, module$exports$vmbootstrap$LongUtils$impl.m_toNativeLong__java_lang_Object(a) returns a number (e.g. 500). As such, it has no method subtract, which is why a TypeError is thrown.

Bazel version 5.1.0

rluble commented 2 years ago

How are you calling testFunctionLong? From JavaScript? So long in Java is not number it is goog.math.Long, and it has a subtract method.

rbsdc commented 2 years ago

@rluble thank you for the reply. Yes, I called it from Javascript. First, I export the functions as follows:

goog.exportSymbol('Test.testFunctionInt', Test.testFunctionInt);
goog.exportSymbol('Test.testFunctionLong', Test.testFunctionLong);

Then I call them from JavaScript like this:

console.log(Test.testFunctionInt(10000, 9500, 1000));
console.log(Test.testFunctionLong(10000, 9500, 1000));

As to your remark:

So long in Java is not number it is goog.math.Long, and it has a subtract method.

Right, this should be the case, or else calling "subtract" on a non-object would always fail. That is, module$exports$vmbootstrap$LongUtils$impl.m_toNativeLong__java_lang_Object(a) should return a object in the transpiled code, but returns a number.

niloc132 commented 2 years ago
console.log(Test.testFunctionLong(10000, 9500, 1000));

It would be a bug to invoke your testFunctionLong in this way, as the first two arguments to testFunctionLong must be goog.math.Long values and not plain JS Number values.

Try instead to export the goog.math.Long.fromInt function to correctly call this:

console.log(Test.testFunctionLong(goog.math.Long.fromInt(10000, goog.math.Long.fromInt(9500), 1000));

Note that if instead of exporting your functions you had instead called them from another JS file that closure read, typechecked, compiled, it would have reported this at compile time.

rbsdc commented 2 years ago

Thank you, again!