代入演算子

 

書式

 

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

 

解説

 

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

 

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

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

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

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

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

 

<<演算子は、左辺のオブジェクトの型と右辺の式の型により挙動が異なります。通常は、左辺のオブジェクトに右辺の値を挿入するような動作となります。代表的な<<演算子は、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を表示していますが、left900に変化した場合Lbl001のみ表示が900となり、Lbl002は変化しません。すなわちLbl001は代入式に参照演算子を使用することでleftを常に参照しており変化が自動的に反映されます。それに対してLbl002には代入時のleftの評価値が格納されており、leftが変化しても反映されません。

 

循環した再計算

計算を実行する順序は最も効率の良い順序に自動的に最適化されます。従って再計算を行う順序は状況により変わることがあり計算順序に依存するような記述を行ってはなりません。

 

参照式の記述によっては、再帰的な再計算で無限ループに陥る可能性があります。例えば次のような式では、再計算は永久に終了しません。

 

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

このような状況は、再計算の実行時に検出されます。式の構文解析では検出されないためイベントハンドラや3項演算子で使用する場合には注意を要します。異常な式として検出されると値の評価が行われる前に実行は中断され、CRS-354例外がthrowされます。

 

参照演算子の制約

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

 

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

インタプリタが更新動作を検出するとCRS-159例外をthrowします。更新操作とは、++--演算子、オブジェクトの変更、生成、削除を伴うメソッド、関数の呼び出しなどが該当します。たとえば以下の記述はエラーとなります。

 

A &= B++;

 

また、ユーザ定義関数の呼び出しは、インタプリタにより呼び出し元とは別のスタックフレームが割り当てられるため、内部的なオブジェクトの生成を伴います。したがって、ユーザ定義の関数を参照式の右辺に記述して呼び出すことはできません。

 

2. //から始まるオブジェクトツリーに接続されているか、グローバル名前空間に置かれていること。

var変数や、newで生成してオブジェクトツリーに接続されていないオブジェクトは利用できません。

 

3. 名前を持つこと

newやオブジェクト固有のメソッド(FileSystem.open()メソッドが返すFileオブジェクトなど) により生成されるオブジェクト、またはイベントハンドラに渡されるイベントオブジェクトなど、固有の名前を持たない無名のオブジェクトを右辺に記述することはできません。

 

 

参照演算子の左辺には、以下の条件を満たすオブジェクトまたはプロパティを指定することができます。var変数やそのほかの要素を指定することはできません。

 

1. //から始まるオブジェクトツリーに接続されていること

var変数や、グローバル名前空間に置かれているオブジェクト、またはnewなどにより生成されオブジェクトツリーに接続されていないオブジェクトは利用できません。

 

2. 名前を持つこと

newやオブジェクト固有のメソッドにより生成されるオブジェクト、またはイベントハンドラに渡されるイベントオブジェクトなど、固有の名前を持たない無名のオブジェクトを左辺に記述することはできません。

 

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

 

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

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

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

 

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

この例は、L2ListBoxの選択位置と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;
    }
}

 

(注)配列要素の位置を特定しないindexプロパティは、過去のバージョンとの互換性維持のためChangeProfile関数の影響を受けます。詳細は、グローバル関数 ChangeProfileを参照してください。

 

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

プロパティは、オブジェクトに用意される固有のメソッドでアクセス可能な場合があります。たとえば、SpreadオブジェクトのGetCell()メソッドは、Spread以下に配置されるSpreadRowのさらに下位に位置するSpreadColumnオブジェクトのvalueプロパティを返します。

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

 

Label Lab1 {
    :
    Value &= F.Spread1.GetCell(0,0);
    /* Value &= F.Spread1.SpreadRow[0].C1 と同じ値を得ます */
}
Spread Spread1 {
    :
    SpreadRow SpreadRow[4] {
        :
        SpreadColumn c1;
        SpreadColumn c2;
    }
}
:
 
Spread1.SetCell(0,0,"set data");

 

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を更新してもA20のままとなります。

 

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の自動再計算も解除されます。

 



「オンラインマニュアル」一覧へ戻る
「Bizの宝箱」TOPへ戻る