オブジェクトとメンバ

この章では、#Script におけるオブジェクトについて定義する。

オブジェクトとメンバの定義

スクリプトによる処理の対象となる数や関数をオブジェクトと総称する。 オブジェクトは、それに付属するデータとしてメンバおよび内部メンバを 持つことができる。(厳密には、オブジェクトとはメンバと内部メンバの集合である)

メンバは名前の組み合わせから成る。名前は一つの Unicode 文字列であり、 値は一つのオブジェクトである。一つのオブジェクトは複数のメンバを持ち得るが、 それらはすべて異なる名前でなければならない。

またオブジェクトはメンバとは独立して内部メンバも持ち得る。 内部メンバは言語仕様の記述の簡便のために定義される形式的な存在であり、 スクリプトプログラムによって直接扱うことはできない。 内部メンバはメンバと同じく名前と値から成るが、 内部メンバの値はオブジェクトに限らない。

一つのオブジェクトには同じ名前のメンバと内部メンバが存在しても良い。 メンバと内部メンバは独立しているので、同名のメンバと内部メンバは 一般に異なる値を持つ。

名前にドル記号 $ を含むメンバの一部は、#Script 言語において特殊な意味を持つ。プログラマは、この言語仕様で定めた所定の効用 (メンバのゲッターや演算子の定義) を得る以外の目的で名前にドル記号を含むメンバを使用すべきでない。

オブジェクトの同一性

オブジェクトが持つメンバ・内部メンバは、 それらに対して明示的に変更が行われない限り、変化しない。

二つのオブジェクトが同じであるとは、そのオブジェクトが存在している 任意の時刻において、常に次の同値関係が成り立つことをいう: 一方のオブジェクトの任意のメンバ・内部メンバについて、 もう一方のオブジェクトも同じ名前と値のメンバ・内部メンバを持つ。

二つのオブジェクトが同じでない (異なる) ならば、 それらのオブジェクトのメンバ・内部メンバは独立している。すなわち、異なる二つの オブジェクトについて、一方のオブジェクトのメンバ・内部メンバが変化しても、 もう一方のオブジェクトのメンバ・内部メンバは直接その変化の影響を受けない。

新しくオブジェクトが作られるとき、 その新しいオブジェクトは既に存在している他のいかなるオブジェクトとも異なる。

型とプロトタイプ

オブジェクトがそのような種類のメンバを持っているかという観点による オブジェクトの区別をという。#Script のオブジェクトは一般にオブジェクトの生成後にもメンバの追加や削除が行えるため、 一般にオブジェクトの型は不変ではない。

オブジェクトに $prototype という名前の内部メンバが存在する時、 その値はオブジェクトでなければならない。オブジェクトの $prototype 内部メンバの値を、そのオブジェクトのプロトタイプオブジェクトまたは単にプロトタイプという。一般には、 オブジェクトのプロトタイプは不変ではない。また、全てのオブジェクトに $prototype 内部メンバが存在するわけではないので、 全てのオブジェクトがプロトタイプを持つわけではない。

次の条件のどちらかが満たされるとき、オブジェクト P はオブジェクト O準プロトタイプ (オブジェクト) であるという:

すなわち、準プロトタイプとはオブジェクトの間接的なプロトタイプのことである。

任意のオブジェクトについて、そのオブジェクトの準プロトタイプの個数は 有限でなければならない。すなわち、任意のオブジェクト O について、 次のどちらかが成り立つ:

注意: この規則は、操作 search-property がアルゴリズムとして必ず終了するために重要である。 この規則は、任意のオブジェクトはそれ自身を準プロトタイプとすることはできない ということを含意する。

インスタンス

オブジェクト Tprototype という名前のメンバが存在し、そのメンバの値がオブジェクト O のプロトタイプであるとき、OT真のインスタンスであるという。また、 オブジェクト Tprototype という名前のメンバが存在し、そのメンバの値がオブジェクト O の準プロトタイプであるとき、OTインスタンスであるという。

プロパティとメソッド

オブジェクト O を参照先オブジェクトとし Unicode 文字列 n を参照先メンバ名とするメンバ参照に対して操作 check-property を行うと結果が [[初期の Boolean.true]] となり、かつ get-property/set-property/delete-property を行ったときにも何らかの意味のある結果が得られるならば、 On という名前のプロパティを持つという。 あるプロパティに対する操作 get-property の結果が常にオブジェクトを値とする 正常終了の結果となるとき、その結果の値をそのプロパティの値という。 プロパティの値が関数オブジェクトであるとき、 それを特にメソッドという。また、プロパティの値が常に同じ オブジェクトであるとき、そのプロパティは不変であるという。

あるプロパティに対して操作 get-property を行うことを、そのプロパティの値の取得という。また、 プロパティに対して操作 set-property を行うことをそのプロパティに対する代入といい、操作 delete-property を行うことをそのプロパティの削除という。

あるプロパティに対する代入および削除の結果が常に ReadOnlyError のインスタンスを値とする エラー終了となるとき、そのプロパティは読み取り専用であるという。

オブジェクトのプロパティへのアクセス

スクリプトプログラムからオブジェクトのプロパティを利用することを プロパティへのアクセスという。言語仕様の記述の簡略のため、 プロパティへのアクセスに関するいくつかの操作を以下に定める。

プロパティの探索

オブジェクトのプロパティを特定するための操作 search-property は、一つのオブジェクト o と Unicode 文字列 n に対して以下の処理を行い、一つのオブジェクトかまたは void という特殊な値を結果として返す:

  1. on を名前とするメンバが存在するならば、 そのメンバの値を返す。
  2. o がプロトタイプオブジェクトを持たなければ、void を返す。
  3. o のプロトタイプオブジェクトを改めて o として、search-property 処理の始めに戻る。

スクリプトプログラムによるプロパティの存在の確認

スクリプトプログラムによるプロパティの取得に使われる操作 check-property はメンバ参照 r に対して次のことを行う:

  1. r の参照先オブジェクトを o、参照先メンバ名を n とする。
  2. n の先頭に文字列 $get$ を付加してできる新しい Unicode 文字列n′ とする。操作 search-propertyon′ に対して行い、その結果を v′ とする。
  3. v′ が関数として呼出し可能なオブジェクトならば、[[初期の Boolean.true]] を返す。
  4. 操作 search-propertyon に対して行い、その結果を v とする。
  5. v がオブジェクトならば、[[初期の Boolean.true]] を返す。
  6. [[初期の Boolean.false]] を返す。

操作 check-property では、オブジェクトにプロパティが存在するかどうかを調べることが出来る。 詳細は以下の get-property の説明を参照の事。

スクリプトプログラムによるプロパティの取得

スクリプトプログラムによるプロパティの取得に使われる操作 get-property はメンバ参照 r に対して次のことを行う:

  1. r の参照先オブジェクトを o、参照先メンバ名を n とする。
  2. n の先頭に文字列 $get$ を付加してできる新しい Unicode 文字列n′ とする。操作 search-propertyon′ に対して行い、その結果を v′ とする。
  3. v′ が関数として呼出し可能なオブジェクトならば、o を @this 値とし引数無しでこの関数を呼出す。 この結果がオブジェクトを値とする正常終了であるか、 正常終了以外の結果であるならば、それを返す。 それ以外の正常終了の結果ならば、新しい UnsupportedOperationError のインスタンスを投げる。
  4. 操作 search-propertyon に対して行い、その結果を v とする。
  5. [[v]] を返す。

操作 get-property では、オブジェクトが持つプロパティ取得のための メソッドを呼出すことによって、実際に取得される値をオブジェクトが 制御できるようにする。

例えば参照先メンバ名 abc について操作 get-property を行うとき、 オブジェクトが $get$abc という名前のメソッドを持っていれば、 そのメソッドを呼出してその結果を操作 get-property の結果とする。 これにより、$get$abc というメソッドは abc というプロパティに対するゲッターとなる。

ゲッターとして実行される関数は、get-property が取得しようとしている プロパティの値を左辺式で取得しようとしてはならない。 例えば以下のようなコードでは、操作 get-property とゲッターの呼出しが再帰的に際限なく繰り返されてしまう:

obj.$get$prop = @{ @return @this.prop; };
@printline obj.prop;

ゲッターは、代わりに # で始まる名前のメンバを使用できる:

obj.$get$prop = @{ @return #prop; };

ゲッター関数が存在しなければ、オブジェクトが持つそのプロパティの値が そのまま返される。プロパティが存在しなければ、get-property の結果は void となる。

スクリプトプログラムによるプロパティへの代入

スクリプトプログラムによるプロパティへの代入に使われる操作 set-property はメンバ参照 r とオブジェクト p に対して次のことを行う:

  1. r の参照先オブジェクトを o、参照先メンバ名を n とする。
  2. o$isImmutable という名前の内部メンバが 存在すれば、新しい ReadOnlyError のインスタンスを投げる。
  3. n の先頭に文字列 $set$ を付加した 新しい Unicode 文字列n′ とする。操作 search-propertyon′ に対して行い、その結果を v′ とする。
  4. v′ が関数として呼出し可能なオブジェクトならば、o を @this 値とし p を引数としてこの関数を呼出し、 その結果を返す。
  5. v′ が 初期の Boolean.false ならば、新しい ReadOnlyError のインスタンスを投げる。
  6. o の、n を名前とするメンバの値を p に変更する。このようなメンバが存在しないときは、on を名前とする新しいメンバを作成した上で値を p とする。
  7. [[p]] を返す。

操作 set-property では、オブジェクトが持つプロパティ設定のための メソッドを呼出すことによって、実際にプロパティを設定する動作をオブジェクトが 制御できるようにする。(このメソッドは操作 delete-property でも使われる)

例えば参照先メンバ名 abc について操作 set-property を行うとき、 オブジェクトが $set$abc という名前のメソッドを持っていれば、 set-property に渡されたオブジェクトを引数としてそれを呼出し、その結果を返す。 これにより、$set$abc というメソッドは abc というプロパティに対するセッターとなる。

$set$abc が関数ではなく false である場合は、メンバの値は変更されず、ReadOnlyError が投げられる。 プロパティ $set$abcfalse にしておくことで、 プロパティ abc は事実上読み取り専用プロパティとなる。

セッターは、set-property が設定しようとしているプロパティを左辺式への代入によって設定しては ならない。例えば以下のようなコードでは、操作 set-property とセッターの呼出しが再帰的に際限なく繰り返されてしまう:

obj.$set$prop = @[x]{ @this.prop = x; @return x; };
obj.prop = 1;

セッターは、代わりに # で始まる名前のメンバを使用できる:

obj.$set$prop = @[x]{ #prop = x; @return x; };

セッターは、代入されたオブジェクトを戻り値として返すのが望ましい。

セッター関数が存在しなければ、指定されたオブジェクトがメンバとして そのまま設定される。

$isImmutable 内部メンバは、オブジェクトの不変性を示す。 この内部メンバが存在するオブジェクトは不変であり、メンバを変更できない。 (→Object.isImmutableObject.makeImmutable)

スクリプトプログラムによるプロパティの削除

スクリプトプログラムによるプロパティの削除に使われる操作 delete-property はメンバ参照 r に対して次のことを行う:

  1. r の参照先オブジェクトを o、参照先メンバ名を n とする。
  2. o$isImmutable という名前の内部メンバが 存在すれば、新しい ReadOnlyError のインスタンスを投げる。
  3. n の先頭に文字列 $set$ を付加した 新しい Unicode 文字列n′ とする。操作 search-propertyon′ に対して行い、その結果を v′ とする。
  4. v′ が関数として呼出し可能なオブジェクトならば、o を @this 値とし引数無しでこの関数を呼出し、その結果を返す。
  5. v′ が初期の Boolean.false ならば、新しい ReadOnlyError のインスタンスを投げる。
  6. on を名前とするメンバが存在すれば、そのメンバの値を v とした上で、そのメンバを削除し、[[v]] を返す。
  7. [[初期の Void.void]] を返す。

操作 delete-property では、オブジェクトが持つプロパティ設定のための メソッドを呼出すことによって、実際にメンバを削除する動作をオブジェクトが 制御できるようにする。(このメソッドは操作 set-property でも使われる。操作 set-property で使われるときは、呼出しにおける引数の個数が異なる)

例えば参照先メンバ名 abc について操作 delete-property を行うとき、オブジェクトが $set$abc という名前のメソッドを 持つならば、引数無しでそれを呼出し、その結果を返す。

$set$abc が関数ではなく false である場合は、メンバの値は削除されず、ReadOnlyError が投げられる。 プロパティ $set$abcfalse にしておくことで、 プロパティ abc は事実上読み取り専用プロパティとなる。

セッター関数が存在しなければ、そのまま当該メンバがオブジェクトから そのまま削除される。

delete-property では、オブジェクト自身が持つメンバのみを削除する。 プロパティの値がオブジェクトのプロトタイプオブジェクトから得られる場合では、 メンバは削除されない。

© 2006-2007 Magicant