Spec-Zone .ru
спецификации, руководства, описания, API

Свяжите Обновление

Что действительно "связывает" среднее значение?

Когда Вы пишете связанное выражение:

def x = bind someExpression; 

это означает, что, когда someExpression изменяется, x будет обновлен, чтобы соответствовать. Вот именно. В большинстве случаев это - все, что Вы должны знать. Но в некоторых случаях Вы должны знать, как точно обновление происходит и в некоторых случаях, что предназначается изменением someExpression. Они обсуждаются ниже.

Что повторно вычисляется на обновление?

В пределах связывания делается минимальный перерасчет - это только имеет значение при ограниченных обстоятельствах, например когда объектное создание приканчивается связывание и если из-за объектных идентификационных данных имеет значение, если новый объект создается или нет.

Давайте смотреть на пример, свяжите:

def sum = bind expr1 + expr2; 

если значение expr2 изменяется тогда, дополнение делается заново, но expr1 не повторно вычисляется, его значение было сохранено, и это просто повторно выбирается.

Давайте сделаем этот бетон:

var y = 3; 
function ten() : Integer { 
   println("Called ten");
   10 
} 
def sum = bind ten() + y; 
println(sum); 
y = 7; 
println(sum); 

Это печатает:

Called ten
13 
17 

Отметьте, что функция десять () вызывается, чтобы вычислить начальное значение суммы, но когда y устанавливается в 7, функция десять () не вызывается снова (так как это не изменялось), его значение помнили и снова использовано.

Условные выражения

def x = bind if (condExpr) expr1 else expr2;

если значение изменений condExpr, это переключается, какое ответвление оператора "if" должно быть оценено, таким образом вызывая перерасчет каждый раз значение изменений condExpr (предыдущее значение ответвления не сохранено). Если condExpr будет истиной, то изменение к зависимостям expr1 заставит это быть повторно вычисленным, но это не будет вызывать вычисление expr2, ни будут изменения к зависимостям expr2. Определенно, если condExpr будет истиной, то только expr1 будет вычисленный; expr2 не будет. Инверсия является, конечно, также истиной.

Для Выражений

def newSeq = bind for (elem in seq) expr;

Если seq изменяется, элементы в newSeq, который соответствовал элементам все еще в seq, не повторно вычисляются. Таким образом, если элемент вставляется в seq, результат применения expr к тому элементу вставляются в newSeq в соответствующей позиции, и другие элементы не повторно вычисляются. Ну, OK, есть исключение к тому правилу, если expr будет использовать indexof элемент тогда те элементы, чьи индексируют измененный, то должен будет быть обновлен, но снова, соответствуя минимальным правилам обновления. Например:

var min = 0;
var max = 3;
function square(x : Integer) : Integer { x*x }
def values = bind for (x in [min..max]) square(x);  1
println(values);
max = 5;  2
println(values);
min = 1;  3
println(values);
min = 0;  4
println(values);

Вывод:

[ 0, 1, 4, 9 ]  1
[ 0, 1, 4, 9, 16, 25 ]  2
[ 1, 4, 9, 16, 25 ]  3
[ 0, 1, 4, 9, 16, 25 ]  4

Но что относительно перерасчетов?

1

сначала квадраты от 0 до 3 вычисляются

2

тогда квадраты 4 и 5 (0 до 3 не повторно вычисляются когда максимальные изменения),

3

тогда квадрат нуля удаляется (не повторно вычисляя значений)

4

и затем квадрат нуля добавляется назад (это действительно требует, чтобы это было повторно вычислено),

Поведение является тем же самым, если вставляют и удаляют, используются.

[Чтобы сделать: indexof]

[Чтобы сделать: добавьте пример пункта на замене]

Блочные Выражения

Блочное выражение является списком выражений, включенных в изогнутые фигурные скобки. Значение блочного выражения является значением заключительного выражения. В пределах связывания единственные выражения, которые могут произойти в незаключительной позиции блочного выражения, являются переменными определениями (определение). Отметьте: некоторая ранняя версия языка может позволить var, но что это будет отвергнуто. Отметьте также, что присвоение (включая инкремент и декремент) запрещается в пределах, связывают. Таким образом у связанного блочного выражения есть форма:

bind { 
   def a = expr;  
   def b = expr;  
   def c = expr;  
   expr 
} 

Поскольку любые изменения к связанному выражению вызывают обновление, и потому что то обновление минимально, легко видеть, что переменные эффективно связываются.

Мы можем вывести, что, в то время как, вставьте, удалите, и т.д. не может произойти в связанном блочном выражении; они не могут произойти в незаключительных позициях, так как они не объявления переменной; и они имеют Пустой тип, таким образом не имеют никакого значения и не могут быть связаны; и таким образом не может произойти в заключительной позиции.

Вызовы функции и Вызовы метода

def val = bind foo(a, b);

Несвязанная функция является той, которая не продолжается со связанным ключевым словом. Для звонков в методы JavaTM или несвязанные функции JavaFXTM, повторно вызывается функция, если какой-либо из параметров изменяется. Однако, тело функции является черным ящиком, зависимости, которые оно могло бы иметь вне параметров, не вызывают перерасчет. Например:

class Point {
  var x : Number;
  var y : Number;
}

var scale = 1.0;
function makePoint(x0 : Number, y0 : Number) : Point {
  Point {
    x: x0 * scale
    y: y0 * scale
  }
}

var myX = 3.0;
var myY = 3.0;
def pt = bind makePoint(myX, myY);
println(pt.x);
myX = 10.0;   1
println(pt.x);
scale = 2.0;  2
println(pt.x);

Напечатает:

3.0 
10.0   1
10.0   2

1

Изменяя параметр myX заставляет makePoint быть вызванным снова.

2

Но, функция makePoint является черным ящиком. Изменение, чтобы масштабироваться не будет вызывать обновление. Это - то, где связанные функции входят.

Связанные Функции

Связанные функции имеют как их тело блочное выражение, которое связывается (у него таким образом есть вышеупомянутые ограничения на связанные блочные выражения). Связывая со связанной функцией, изменения к значениям в выражении тела, не ограниченном параметрами, обновлениями причины, и изменениями параметра, замечаются функцией. Так, если вышеупомянутая функция makePoint была вместо этого связанной функцией:

bound function makePoint(x0 : Number, y0 : Number) : Point { ...

Изменение масштаба вызвало бы обновление (20.0). Отметьте также, это, если бы измененный myX, только x0 * масштаб был бы повторно вычислен, не y0 * масштаб.

Вызывание связанной функции снаружи связывания точно так же как вызывает несвязанную функцию.

Объектные Литералы

Объектные литералы ведут себя как простые операторы (+, и т.д.) и несвязанные функции. Таким образом, если один из параметров объектным литеральным изменениям, то это повторно выполняется (новый экземпляр создается).

def pt = bind Point { 
   x: myX
   y: myY  
}

если myX изменяется, новый Точечный объект создается - это точно, что Вы хотите для неизменных объектов.

Что, если Вы хотите, чтобы значение x отследило значение myX, не создавая новую Точку? Затем Вы связываете инициализаторы переменной экземпляра:

def pt = bind Point { 
   x: bind myX
   y: myY  
}

Теперь, если myX изменится, то x переменная экземпляра точки pt будет обновлена, но новая Точка не будет создаваться, потому что инициализатор переменной экземпляра объектного литерала не изменился (x, все еще, и всегда будет, связано с myX). Изменения к myY все еще заставят новую Точку создаваться.

Так, что Вы, вероятно, хотели бы для этого примера, будет для точки, чтобы отследить myX и myY:

def pt = Point { 
   x: bind myX
   y: bind myY  
}

Здесь pt всегда оставался бы тем же самым экземпляром Точки. Отметьте, что больше нет потребности в, привязывают выражение инициализации pt, так как нет никаких зависимостей.