双方向バインド(bind ... with inverse)


すでに述べたように、双方向のバインドはどちらの方向の流れも更新する、バインド式というよりもむしろ変数です。

var z = bind x with inverse;

ここでは、xが変化したらzがzの値に更新されます。 しかし、with inverseは、zが割り当てられたら(または変化したら)xの値はzの値に変化することを意味します。

例:

var note = "do";
var solfege = bind note with inverse;
println( "note={note},  solfege={solfege}" );
note = "re";         ①
println( "note={note},  solfege={solfege}" );
solfege = "mi";      ②
println( "note={note},  solfege={solfege}" );
note = "fa";
println( "note={note},  solfege={solfege}" );

① 単一方向のバインドと同様に、バインド式の変化が変数を変えます。
② しかし、双方向のバインドでは、バインド変数の変化がバインド式を変えます。具体的には変数がバインド式になります。
note=do,  solfege=do
note=re,  solfege=re          ①
note=mi,  solfege=mi          ②
note=fa,  solfege=fa

それが必ず割り当て可能であることと、 バインド式が変数への参照になることは禁止されていることに注意してください。 この制約は、少々つまらないローカル変数への双方向バインドを作ります。 それらが(上の例にあるように)同じ値のための別名である通りです。 それらが興味深くなる場面は、オブジェクトのインスタンス変数の間でのバインドです。 この例では、PointであるprojectionOnXのインスタンス変数 x が他のPoint(pt)のインスタンス変数に 双方向にバインドされています。

class Point {
  var x : Number;
  var y : Number;
  override function toString() : String { "Point({x},{y})" }
}

def pt = Point {
   x: 3.0
   y: 5.0
}
def projectionOnX = Point {
   x: bind pt.x with inverse
   y: 0.0
}
println( pt );
println( projectionOnX );
pt.x = 7.6;    ①
println( pt );
println( projectionOnX );
projectionOnX.x = 22.2;   ②
println( pt );
println( projectionOnX );
① 単一方向のバインドのように、バインド式の変化がインスタンス変数を変えています。
② しかし、双方向のバインドで、バインド変数の変化がバインド式を変えていて、具体的に言えばインスタンス変数はバインド式になります。
Point(3.0,5.0)
Point(3.0,0.0)
Point(7.6,5.0)
Point(7.6,0.0)          ①
Point(22.2,5.0)         ②
Point(22.2,0.0)

これはユーザインターフェースで特に便利です。例を挙げれば、編集可能なフィールドに保存された値の表示です。 保存された値が変化したら、表示する値を変化させる必要があるだけでなく、 ユーザが値を変更したら、それは保存されなければなりません。


Home