2016-03-10 4 views
0

Я экспериментировал с Nashorn и получил некоторые странные результаты в отношении возвращаемых типов eval().Почему оптимистическая печать Нашорна дает непредсказуемые результаты?

// calculator.js 
var add = function(a, b) { 
    return a + b; 
} 

И следующий Java-код:

// CalculatorTest.java 
import java.io.InputStreamReader; 
import javax.script.* 
import org.junit.* 
import jdk.nashorn.api.scripting.NashornScriptEngineFactory; 

public class CalculatorTest { 

    ScriptEngine nashorn; 

    @Before 
    public void setup() throws ScriptException { 
     NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); 
     nashorn = factory.getScriptEngine("–optimistic-types=true"); 
     nashorn.eval(new InputStreamReader(
       getClass().getClassLoader().getResourceAsStream("calculator.js"))); 
    } 

    @Test 
    public void addViaInvokeFuntion() throws Exception { 
     Object result = ((Invocable) nashorn).invokeFunction("add", 2, 3); 
     Assert.assertEquals(5.0, result); 
    } 

    @Test 
    public void addViaSimple() throws Exception { 
     Object result = nashorn.eval("2+3"); 
     Assert.assertEquals(5, result); 
    } 

    @Test 
    public void addViaMoreComplexEval() throws Exception { 
     Object result = nashorn.eval(
       "var anotherAdd = function(a, b) {\n" + 
       " return a + b;\n" + 
       "};\n" + 
       "anotherAdd(2, 3);"); 
     Assert.assertEquals(5L, result); 
    } 
} 

Почему эти тесты успеха именно таким образом?

Есть ли способ «предсказать» типы возврата Nashorn?

Должно ли оптимистичное типирование делать именно это?

+0

Я второй этот вопрос, когда я наткнулся на это вместе с Майклом. Чтобы быть точнее: почему возвращается «Integer», если операция или функция вызывается непосредственно с помощью «eval()» и почему возвращается «Double», если функция вызывается из внешнего js-файла? Я полностью понимаю, что 'Number' следует использовать, а в JS все - поплавковый. Но помимо этого, почему один раз «Integer» вернулся, а другой - «Двойной»? – dasniko

ответ

1

То, что вы видите здесь, связано с тем, что Nashorn создает специализированные версии функций, основанные на входном типе их параметров (и не оптимистичный набор текста как таковой). Когда вы вызываете add через интерфейс Invocable, вы в конечном итоге ссылаетесь на специализацию add(Object, Object), а не add(int, int). Если типы параметров являются объектами, то нет никакого оптимизма для использования; Вы получаете следующий байт-код:

public static add(Object;Object;Object;)Object; aload 1 aload 2 invokestatic ScriptRuntime.ADD(Object;Object;)Object; areturn

(вы можете проверить это сами, если добавить --print-code к аргументам командной строки двигателя, другой полезной один --log=recompile which'll печати специализаций типа функций, которые были созданы .)

Таким образом, это не имеет никакого отношения к add, определяемому в calculator.js, а скорее к тому, что ваш сайт вызова - Invocable.invokeFunction вводится как принимающий параметры всех объектов.

ScriptRuntime.ADD(Object, Object) не пытается быть слишком умным и узким типом его результата; это реализация оператора медленного пути с общим кодом +, которая используется, когда нет статической информации о типах параметров, и она должна быть подготовлена ​​к рассмотрению странных случаев JavaScripts, таких как "2" + [] и т. д. Его код, безусловно, может содержать специальные случаи оптимизации, такие как «если результат операции соответствует Integer, верните один», но мы решили, что дополнительная сложность не стоит того, что вы потеряли информацию о статическом типе на входе. Следовательно, вы получите двойное значение для всех числовых добавлений, если статический тип параметров равен Object.

Если с другой стороны, вы бы выполнить nashorn.eval("add(2, 3)") тогда он будет вызывать add(int, int) специализации, которая является оптимистичным, и вы на самом деле в конечном итоге с возвращаемым значением является целое число 5.

Надежда, что помогает.

+0

Большое вам спасибо @Attila, это очень помогло понять различия! :-) – dasniko

1

тип Java используется для представления значения JS в реализации аспекта (это не является частью ECMAScript спецификации. До тех пор, как TypeOf говорит «число» и арифметические операции работают, как и ожидалось, любой тип/JVM Java должен быть отлично). Использование Java «int» для значения количества ECMAScript - это оптимизация. Эта оптимизация не может быть выполнена всегда. Можно сделать только безопасный вывод. Сторона Java должна ожидать, что любое значение Число будет возвращено для значения «число» ECMAScript. Эти тесты должны быть написаны для использования типа java.lang.Number. Вы можете вызвать методы «intValue», «doubleValue» для возвращаемого значения (после того, как кастинг возвратил Object как java.lang.Number) и утвердить ожидаемое значение.

+0

Да, как я уже прокомментировал вопрос, я это знаю. На самом деле, я хочу знать, почему это «Integer», когда оценивается непосредственно с помощью 'eval (..)', но «Double», когда загружается и выполняется/оценивается внешний файл с функцией _same_ ... – dasniko

Смежные вопросы