I am using "nashorn" javascript engine in java8 to evaluate some expressions during runtime. I have a util class for this with method:
public static String evaluateJavaScriptExpression(String expression) throws ScriptException {
if (expression == null) {
return null;
}
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine javaScriptEngine = scriptEngineManager.getEngineByName(JAVASCRIPT_ENGINE);
return String.valueOf(javaScriptEngine.eval(expression));
}
for which I created some unit tests. One of them goes like this:
String expression = "var arr = [1, 3, 2, 5, 4]; arr.indexOf(0);";
assertEquals("-1", ExpressionEvaluatorUtil.evaluateJavaScriptExpression(expression));
It worked fine for me while I was using java version "1.8.0_91". But someone who used java version "1.8.0_92" reported that the test is failing. I switched my version to build 92 and it failed for me as well. The actual result for it is "-1.0". Also, i tried the same js code in Chrome console and it is returning "-1" as in build 91.
Does anyone know why there is such difference in results between the two jdk versions? Is this a bug or it was purposely changed?
Well, if you know the precise version number of the change, you know where to look: the list of 1.8u92 bugfixes lists some fixes regarding Nashorn, the most interesting being JDK-8144020:
Remove long as an internal numeric type
ECMA defines double as the only number type in JavaScript. In Nashorn, we internally represent numbers as int, long and double. Use of long is problematic because it adds extra precision to the 53 bits provided by double. …
At the first glance, this seems to be an internal change only, but the picture changes, if you realize that your former result stemmed from the fact that previously, eval
returned a Long
for this code, being formatted to "-1"
.
Now consider the first sentence of this bug report: “ECMA defines double as the only number type in JavaScript”. This leads to the conclusion that returning a Long
was not a specified result type, but an implementation artifact.
So apparently, when long
was removed from the internal usage, the possibility to return Long
was eliminated and the engine now doesn’t return Integer
instead, but Double
, as a byproduct of the change.
This explains, why there are other scripts like "var str = 'abcd'; str.indexOf('x');"
which still produce an output without fractional digits. The latter script evaluated to Integer
and still does. Since the change of the output type was a byproduct of removing internal long
usage, not an intentional action to change all non-Double
numeric results, places internally using int
were not affected.
When comparing the result with Chrome’s engine, you have to consider that you are only comparing formatted output, with the number to string conversion not being part of the script. So the outcome is unspecified. The browser may take the freedom to present all numeric values matching an integer value without fractional digits.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With