1

To dive in, we have an app where we have had Nashorn embedded. With 17 I'm replacing it with GraalJS and there are some issues.
The current one is where I want GraalJS treat a custom class as an int (or double)for the purpose of basic arithmetic (+,- and so on). Right now, Graal.js can't make head or tails of it so it just calls the toString method which isn't optimal.
With Nashorn it sufficed to extend java.lang.Number but that doesn't seem to work here.
I've looked in the interpreter code (I can't find any relevant docs) and that shows that Graal.js can handle the various java.lang classes but I can't figure out how to make it use custom classes.

The custom class has a lot of other func as well so I can't throw it away and we have a large installed base of JS code that uses the custom class(es).

The JS code : function(e){print(e.id + 1)} where e is an object and id is a custom type (JSNumber that extends Number).

With Nashorn this worked (ie if id = 1, the result would be 2).
But, with Graal.js id is treated like a String and we get string concatenation instead, the result is 12.

Any links, hints or tips welcome!

Addendum: this seems to be what I'm looking for : https://www.graalvm.org/latest/reference-manual/js/OperatorOverloading/ or what I want to achieve.

Erik
  • 2,013
  • 11
  • 17

1 Answers1

0

Well, talking to the Graal.js people on their slack channel led to this insight from Jan Štola :

We handle Java objects in the same way as JavaScript objects in JavaScript code. This means that we perform ToPrimitive() conversion when + operator is used. ToPrimitive(o) attempts to invoke o.valueOf() to convert o to a primitive value. If this call does not return a primitive value then it invokes o.toString(). So, one possibility is to add valueOf() methods into your classes (and return something like doubleValue() there).

So adding a valueOf-method solved that problem.

Jan also added a solution if you cannot modify the existing class:

If you don't want to modify your classes then you can define valueOf() method on foreign object prototype (FOP). Every non-JavaScript object (like Java object) has FOP object as its prototype. So, when valueOf() method is not defined on the Java object itself then FOP object is searched for this method. Hence, you can use something like var FOP = Object.getPrototypeOf(new java.lang.Object()); FOP.valueOf = function() { return (this instanceof java.lang.Number) ? this.doubleValue() : Object.prototype.valueOf.call(this); } to ensure that subclasses of java.lang.Number will be converted to the desired value in ToPrimitive() conversion.

Christian Humer added an implementation as well.

Erik
  • 2,013
  • 11
  • 17