代入演算子

書式

オブジェクト[.プロパティ] = ;
オブジェクト[.プロパティ] += ;
オブジェクト[.プロパティ] -= ;
オブジェクト[.プロパティ] *= ;
オブジェクト[.プロパティ] /= ;
オブジェクト[.プロパティ] %= ;
オブジェクト << ;
オブジェクト[.プロパティ] &= ;

解説

=演算子は、式の評価結果を左辺のオブジェクトに代入します。


+=演算子は、式の評価結果を左辺の評価値に加算して左辺のオブジェクトに代入します

-=演算子は、式の評価結果を左辺の評価値に減算して左辺のオブジェクトに代入します

*=演算子は、式の評価結果を左辺の評価値に乗算して左辺のオブジェクトに代入します

/=演算子は、式の評価結果で左辺の評価値を除算して左辺のオブジェクトに代入します

%=演算子は、式の評価結果で左辺の評価値の剰余を左辺のオブジェクトに代入します


<<演算子は、左辺のオブジェクトの型と右辺の式の型により挙動が異なります。

通常は、左辺のオブジェクトに右辺の値を挿入するような動作となります。

代表的な<<演算子は、CSVDocumentオブジェクトにより定義される、CSV定数の挿入です。

Record r1[] {
    Number a;
    Number b;
    Number c;
}
r1 << csv {
1,2,3
4,5,6
7,8,9
1,2,3
};

この例では、配列化されたRecordオブジェクトにCSV定数を挿入しています。


&=演算子は、参照演算子と呼ばれる代入演算子の一種で、オブジェクト間の動的データ参照を定義する場合に使用します。

参照演算子で代入を行うと、式の評価結果が変化したとき、自動的に再計算が実行されます。

Number left = 100;
Label lbl001;
Label lbl002;
lbl001.Value &= left;
lbl002.Value = left;
......
left = 900;

初期状態では画面上のラベル Lbl001, Lbl002共に100を表示していますが、leftが900に変化した場合Lbl001のみ表示が900となり、Lbl002は変化しません。

すなわちLbl001は代入式に参照演算子を使用することでleftを常に参照しており変化が自動的に反映されます。

それに対してLbl002には代入時のleftの評価値が格納されており、leftが変化しても反映されません。


循環した再計算

計算を実行する順序は最も効率の良い順序に自動的に最適化されます。

従って再計算を行う順序は状況により変わることがあり計算順序に依存するような記述を行ってはなりません。


参照式の記述によっては、再帰的な再計算で無限ループに陥る可能性があります。

例えば次のような式では、再計算は永久に終了しません。

A &= B + 1;
B &= A + 1;

このような状況は、再計算の実行時に検出されます。

式の構文解析では検出されないためイベントハンドラや3項演算子で使用する場合には注意を要します。

異常な式として検出されると値の評価が行われる前に実行は中断され、CRS例外がスローされます。


参照演算子の制約

参照演算子の右辺には、以下の条件を満たす式を記述することができます。


  1. 更新動作を伴なわないこと。

インタプリタが更新動作を検出するとCRS例外をスローします。

更新操作とは、++や--演算子、オブジェクトの変更、生成、削除を伴うメソッド、関数の呼び出しなどが該当します。

たとえば以下の記述はエラーとなります。

A &= B++;

また、ユーザ定義関数の呼び出しは、更新動作を伴うか否かを実行時まで判断できません。

したがって、ユーザ定義の関数を参照式の右辺に記述して呼び出すことは禁止されています。


  1. 参照演算子の評価時に値を解決できること

オブジェクトの参照を指定する場合、空参照や存在しないオブジェクト,プロパティを指定することは出来ません。


参照演算子の左辺には、以下の条件を満たすオブジェクトまたはプロパティを指定することができます。

  1. 参照演算子の評価時に値を解決できること

オブジェクトやプロパティを指定する場合、空参照や存在しないオブジェクト,プロパティを指定することは出来ません。


再計算は以下の条件により実行されます。

  1. 右辺で参照しているオブジェクトまたはプロパティが、すべて実際にアクセス可能であること

式中にアクセスできないプロパティが記述されている場合、CRSインタプリタは式の依存性を検証することができません。

そのような場合、正常な再計算は実行されません。

特に、配列化されているオブジェクト中で、indexプロパティを使った再計算には注意が必要です。

ListBox L1 {
    ListItem item1[3];
}
ListBox L2 {
    ListItem item2[3] {
        selected &= F.L1.item1[index].selected;  … 【1】
    }
}

この例は、L2のListBoxの選択位置とL1の選択位置を一致させようとしています。 しかし、このような記述の場合、【1】のスコープでは配列要素固有のプロパティであるindexプロパティはアクセスできません。 従ってこの式では、CRSインタプリタはL1.item1[n].selectedプロパティに対する依存性を検出できず、L1の選択位置が変化しても再計算は実行されません。

正しく再計算を実行するためには、以下のようにして常に参照するプロパティにアクセス可能とする必要があります。

ListBox L1 {
    ListItem item1[3];
}
ListBox L2 {
    ListItem item2[3] {
        selected &= index != null ? F.L1.item1[index].selected : F.L1.item1.selected;
    }
}

  1. 右辺で直接参照しているオブジェクトまたはプロパティが更新されること

プロパティは、オブジェクトに用意される固有のメソッドやユーザ定義関数などでアクセス可能な場合があります。

下記の例では、TextBoxに用意されたユーザ定義関数から値を取得し参照演算子によって値を再計算しようとします。

CRSインタプリタは、このようなプロパティへの間接的なアクセスによる依存性を検出することはありません。従って次の例は再計算は実行されません。

TextBox TextBox1 {
    :
    Value = "123";

    Function getValue(){
        return this.value;
    }
}
Label Label2 {
    :
    /* Value &= ^.TextBox1.value; */
    Value &= ^.TextBox1.getValue();
}

GetCellの式の代わりに、コメントアウトされている式を記述した場合には、実際にアクセスするプロパティを直接記述しているため、再計算が実行されます。


3.配列化されたオブジェクトの再計算は、配列要素の若い順に実行されます。

配列要素の再計算順序は常に若い要素から開始されます。


参照演算子の解除

再計算式による自動計算は、計算対象のオブジェクトの削除、再計算式の基点となるオブジェクトの削除、または別の値の代入により解除されます。

A &= B + 1;   【1】
   :
B = 5;        【2】
A = 20;       【3】
B = 6;        【4】

この例では、【1】でAに対して再計算を指定しているので、【2】でBに5が代入されるとAは自動的に6となります。 次に【3】でAに対して20を代入しているので、この時点でAに対する自動再計算は解除されます。 従って【4】でBを更新してもAは20のままとなります。

Form F1 {
    TextBox T1 {
        :
    }
    Label L1;
    Label L2 {
        :
        F1.T1.Value &= F1.L1.value * 2;
        Function OnClick(e) {
            delete();
        }
    }
}

この例の場合、T1.Valueの値をL1.Value * 2で自動再計算しますが、L2のタップでL2は削除されます。 この場合、T1.Valueの再計算式はL2オブジェクトを基点(this)として実行する必要があるのに対して、 L2オブジェクトは存在しなくなるのですから、T1.Valueの自動再計算も解除されます。