クラス

この章ではクラスの概要について説明します。具体的には、以下の項目について説明します。

クラス入門

要約:
  • クラスは有効なデータ型です。
  • クラス メンバには、フィールド、オプション、メソッドおよびアクセッサがあります。
  • アクセス属性によって、クラスまたはクラス メンバにアクセスできるコードを制限できます。
  • 修飾子は、定義の継承、コンパイル、操作を制御します。
  • クラスは多重継承をサポートしています。
  • Curl 言語は抽象クラスをサポートしています。
  • Curl 言語はパラメータ化クラスをサポートしています。
クラスはオブジェクト指向プログラム構築の基礎的なビルディング ブロックとなるものです。 クラスはデータ型の 1 つで、その性質と動作によって構成されます。つまり、データ (フィールドと呼ばれます) およびデータを操作するプロシージャ (メソッドと呼ばれる) で構成されるということになります。コード内ではクラスを使用してオブジェクトを作成することができます。 オブジェクトはクラス型のインスタンスです。Curl® 言語には ArrayStringBuf のようなコードで使用できる組み込みのクラスが多数用意されていますが、 独自のクラスを作成することもできます。
多くのオブジェクト指向プログラム言語と同じように、Curl 言語のクラスには値を保存するためのフィールドと動作を定義するためのメソッドがあります。 クラスには getterssetters と呼ばれるメンバもあります。これらは、両方とも accessors と呼ばれています。 ゲッターとセッターとは計算済みのフィールドのような特別のタイプで、フィールド値が検証される場合、または、値が新たに割り当てられた場合にコードを実行することができます。アクセッサはメソッドと同じ方法では呼び出しません。代わりに、フィールド名のようにアクセッサの名前を扱います。
クラスにはオプションを伴うものがあります。オプションを使用してオブジェクトの属性を保存します。オプションは、ダイアログ、フィールド、ボタンまたはシェイプなどの可視オブジェクトのために特別にデザインされています。この点において、オプションはフィールドより多くの利点を提供します。これらの利点については、それぞれのオプションの解説を参照していただければ明らかになります。
Curl 言語ではクラス内で変数を定義することもできます。フィールドはクラスのインスタンスそれぞれに固有のものですが、クラス変数はインスタンスではなくクラス自体に関連付けられています。したがって、クラスのすべてのインスタンスが共有する定義においてクラス変数を使用することができます。 また、クラス定数やクラス プロシージャに加えてクラス変数を使用することで、グローバル名前空間の識別子の数を減らすことにもなります。
コンストラクタとファクトリーは、クラスのインスタンスの作成を制御するものです。
クラスとそのメンバにはアクセス属性があります。アクセス属性により、クラスおよびクラス メンバの定義にアクセスできるコードが決まります。クラスとそのメンバには、それらの操作に影響を与える修飾子もあります。これらの修飾子は、継承 (finalsealed および open) 、コンパイル (inline および implicit)、および操作 (abstract, shared および weak) を制御できます。修飾子の中には、特定の種類の定義にのみ適用されるものがあります。各種の定義に適用されるアクセス属性および修飾子の詳細については、定義の構文の説明を参照してください。
Curl 言語は多重継承をサポートしています。これは、クラスが 1 つまたは複数のスーパークラスを継承できるということです。スーパークラスやサブクラスという用語は、互いに継承するクラス間の関係を参照する場合に使用します。サブクラスはスーパークラスからクラス メンバを継承します。

クラスの定義

クラスを定義するには、 define-class を使用します。
構文:{define-class [access] [modifier-list] ClassName [{inherits superclass-list}]
    members
}
説明:
accessアクセス属性です。有効な属性は publiclibrary および package です。access を指定しない場合、アクセス属性は既定の package になります。詳細は「クラスへのアクセス」を参照してください。
modifier-listオプションの修飾子のリストです。有効な修飾子は abstractsharedfinalsealedopenserializable および deprecated です。複数の修飾子を指定する場合は修飾子の間に空白文字を使用します。詳細は「クラス修飾子の指定」を参照してください。
ClassNameクラスの名前です。Curl 言語の命名規則では、クラス名は大文字で始めます。クラス名が複数の単語で構成される場合、単語を連結して各単語の最初の文字を大文字にします。
superclass-listこのクラスがコードを継承する、オプションのクラス名のリストです。複数のクラスからコードを継承することができます。クラスが複数のクラスからコードを継承する場合は、クラス名を区切るためにカンマを使用します。
membersクラスのコードです。メンバにはフィールド、アクセッサ、オプション、メソッド、コンストラクタおよびファクトリーの定義を含めることができます。追加するクラス メンバやオーバーライドの必要がある継承したクラス メンバについて定義を指定します。
注意: access および modifier-list は任意の順序で指定できます。たとえば、
{define-class public final ...}
および
{define-class final public...}
はどちらも有効です。
次のコードは Mule というクラスを作成します。これは HorseDonkey の両方のサブクラスです。クラスは public で、修飾子はありません。
{define-class public Mule {inherits Horse, Donkey}
  || Contents of class.
  ...
}

クラスのアクセス属性の指定

アクセス属性は、クラスにアクセスできるコードを示すものです。次の表では有効なクラスのアクセス属性について説明します。
アクセス属性説明
publicパブリック クラスであることを示します。パブリック クラスにはすべてのコードがアクセスできます。
libraryライブラリ クラスであることを示します。同じライブラリ内にある全てのコードがアクセスできます。
packageパッケージ クラスであることを示します。このクラスには、定義されているクラスと同じパッケージ内のコードのみアクセスできます。
注意: パッケージ プロテクトのクラスでは、public アクセス属性を持つコンストラクタまたはファクトリーを作成できません。
クラスの既定のアクセス属性は package です。クラスおよびクラス メンバへのアクセスの詳細については、「クラスおよびクラス メンバへのアクセス」を参照してください。

クラス修飾子の指定

修飾子は、クラスの継承および操作を制御するものです。次の表では有効なクラスの修飾子について説明します。
修飾子説明
abstract抽象クラスでは、そのサブクラスによる実装が必要なインターフェイスを定義します。抽象クラスは直接インスタンス化できません。
注意: 抽象クラスの正式な定義は「少なくとも 1 つの抽象メソッドを持つクラス」です。抽象メソッドには実装がなく、インターフェイスを定義するだけです。抽象クラスのサブクラスが抽象クラスでない場合、抽象メソッドの実装が必要です。
final定義されているクラスを他のクラスが継承できないことを示します。つまり、クラスがサブクラス化できないことを指定するために、この修飾子を使用します。詳細は「継承」を参照してください。
sealed同じパッケージ内のクラスのみが直接このクラスを継承できることを示します。つまり、この修飾子を使用すると、直接のサブクラスはこのクラスと同じパッケージに確実に属していることになります。パッケージ クラスの既定のオーバーライド属性は sealed です。ただし、パッケージの外側にあるシールド クラスは、そのクラスのパブリック オープン サブクラスを継承した場合にこれを間接的にサブクラス化することができることに留意してください。詳細は「継承」を参照してください。
openパッケージの外側のクラスによって継承 (サブクラス化) できるクラスであることを示します。public アクセスのクラスの既定のオーバーライド属性は open です。
注意: コンパイラ ディレクティブ allow-implicit-open? = false が有効である場合 (コンパイラ ディレクティブの stringent? = true によって暗黙的に指定されます)、 定義する各クラス (および各メソッド) のオーバーライド属性を opensealed または final に指定する必要があります。詳細は「コンパイラ ディレクティブ」の章を参照してください。
shared他のクラスによって 1 回以上継承 (サブクラス化) されたクラスは、そのクラスの各インスタンスに対してフィールドのコピーがそれぞれ 1 つだけ保持されるということを示します。詳細は「継承」を参照してください。
serializableこのクラスのインスタンスをシリアル化または非シリアル化することができることを示します。詳細に関しては、「シリアル化」 を参照してください。
deprecated新しいコードではこのクラスの使用が推奨されていないことを示します。クラスは現在はサポートされていますが、将来削除される可能性があります。
任意の数の修飾子を指定できます。複数の修飾子を指定する場合は、空白文字を使用して修飾子を区切ります。

クラス メンバ入門

要約:
  • フィールドはデータを保持します。
  • アクセッサはフィールドへのアクセスを制御します。
  • メソッドは関数を実行します。
  • クラス変数および定数はグローバル変数および定数に似ています。
  • クラス プロシージャはグローバル プロシージャに似ています。
  • オプションは属性を保持します。
クラスには以下のメンバを含めることができます。
クラスのフィールドにはデータを格納します。クラス内で任意の数のフィールドを宣言することができます。宣言するフィールドに任意の有効なデータ型を指定することができます。たとえば intString、または Array-of フィールドを指定できます。フィールド宣言ではフィールドの内容を初期化します。
フィールドへのアクセスを制御するためにアクセッサを記述することもできます。アクセッサには、ゲッターとセッターの 2 つのタイプがあります。ゲッターはフィールドの値の読み取りを制御し、セッターはフィールドへの値の書き込みを制御します。アクセッサには、それを呼び出す構文を簡略化できるという利点があります。つまり、アクセッサの名前をフィールド名のように扱うことができます。したがって、アクセッサの呼び出しは単純なフィールド参照のように見えます。
オプションは追加のメカニズムで、オブジェクトのオプションの属性 (通常は可視属性) を保存するために使用します。単純なフィールド参照と同じ表記法でアクセスできますが、オブジェクトに新しいオプション値が設定されると追加のコードが実行されるという点でアクセッサに似ています。
注意: フィールド、アクセッサおよびオプションをまとめて、オブジェクトのプロパティと呼ぶこともあります。詳細は「オブジェクトのプロパティ」を参照してください。
オブジェクト上で関数を実行するにはメソッドを使用します。メソッドは引数を受け取り、ゼロまたはそれ以上の値を返すことができます。
クラス変数または定数は、クラス内で定義されるグローバル変数のようなものです。クラス プロシージャは、クラス内で定義されるグローバル プロシージャのようなものです。クラスのすべてのインスタンスが共有する定義において、クラス変数、定数およびプロシージャを使用することができます。また、次のような理由でクラス変数、定数およびプロシージャを使用する場合があります。
クラスの中にはオプションを使用して、結果として生成されるオブジェクトの属性を保存できるものがあります。オプションは、ダイアログ、フィールド、ボタンまたはシェイプなどの可視オブジェクト用にデザインされています。オブジェクトの幅、高さ、色などの情報は、オプションに保存されるのが一般的です。言い換えると、オプションを通常使用してオブジェクトの可視属性を保存します。オプションはこの目的で特別にデザインされていて、このような情報の取り扱いに関して他の方法よりも多くの利点を備えています。

クラスへのアクセス

要約:
  • アクセス属性は packagelibrary および public です。
特定のクラス型のオブジェクトを定義して使用するためには、コードがそのクラス定義にアクセスできることが必要です。クラス定義へのアクセスは、以下の条件によって決定されます。
アクセス属性が public の場合、すべてのコードはクラス定義にアクセスできます。アクセス属性が package の場合は、同じパッケージ内のコードしかクラス定義にアクセスできません。library アクセス属性の詳細な情報については library をご覧下さい。
コードがクラス定義にアクセスできる場合、以下を実行することができます。
ただし、クラス定義にアクセスできるコードで常にそのクラスのインスタンスが作成できるわけではありません。クラスのコンストラクタやファクトリーのアクセス属性によって、クラスをインスタンス化できるコードが決まります。

クラス メンバへのアクセス

要約:
  • クラス メンバにアクセスするには、 object-name.member-name のように指定します。
  • メンバが同じクラスにある場合は、 self.member-name> のように指定します。
  • メンバがスーパークラスにある場合は、super.member-name または super.ClassName.member-name のように指定します。
  • コンストラクタを呼び出すには、 {construct-super} のように指定します。
オブジェクトのクラス メンバにアクセスするためには、そのオブジェクトを参照する必要があります。次の構文を使用します。
構文:
object-name.member-name
説明:
object-nameオブジェクトの名前です。
member-nameクラス メンバの名前です。
たとえば、on-pointer-enterCommandButton クラスのメソッドです。my-buttonCommandButton 型のオブジェクトで、my-eventPointerEvent 型のオブジェクトの場合、my-buttonon-pointer-enter メソッドにアクセスするには次のように記述します。
{my-button.on-pointer-enter my-event}
クラス内のクラス メンバ (クラスの特定のインスタンスの) にアクセスするには 、コードで次の構文を使用します。
構文:
self.member-name
説明:
member-nameクラス メンバの名前です。
Curl® 実行環境 (RTE) が self で始まるメンバ式を評価するときはクラスの現在のインスタンスの member-name を呼び出します。たとえば、CommandButton クラスのサブクラスの定義から on-pointer-enter メソッドにアクセスするには、次のように記述します。
{self.on-pointer-enter my-event}
サブクラスの定義内からクラス メンバにアクセスするには次の構文を使用します (コンストラクタは例外で、この構文はこの下に示します)。
構文:
super[.ClassName].member-name
説明:
ClassNameクラスの名前です。クラスが複数のスーパークラスを継承する場合、ClassName を指定します。
member-nameクラス メンバの名前です。
サブクラスの定義内からコンストラクタにアクセスするには次の構文を使用します。
構文:
construct-super[.ClassName] [.constructor-name]
説明:
ClassNameクラスの名前です。クラスが複数のスーパークラスを継承する場合は ClassName を指定します。
たとえば、次の式ではスーパークラスのコンストラクタを呼び出して、メソッド呼び出しの引数を指定していません。
{construct-super}
クラス メンバにアクセスするには、次の両方の種類のアクセスが必要です。
次の図は、public クラスのメンバにアクセスできるコードを示しています。
パッケージ A
パブリック クラス A1
a (public)
b (package)
c (protected)
d (private)
クラス A2 (A1 を継承)
A1 の a にアクセス可能
A1 の b にアクセス可能
A1 の c にアクセス可能
A1 の d にはアクセス不可
クラス A3
A1 の a にアクセス可能
A1 の b にアクセス可能
A1 の c にアクセス可能
A1 の d にはアクセス不可
パッケージ B
クラス B1 (A1 を継承)
A1 の a にアクセス可能
A1 の b にはアクセス不可
A1 の c にアクセス可能
A1 の d にはアクセス不可
クラス B2
A1 の a にアクセス可能
A1 の b にはアクセス不可
A1 の c にはアクセス不可
A1 の d にはアクセス不可
Figure: パブリック クラスのメンバへのアクセス
次の図は、package クラスのメンバにアクセスできるコードを示しています。
パッケージ A
パブリック クラス A1
a (public)
b (package)
c (protected)
d (private)
クラス A2 (A1 を継承)
A1 の a にアクセス可能
A1 の b にアクセス可能
A1 の c にアクセス可能
A1 の d にはアクセス不可
クラス A3
A1 の a にアクセス可能
A1 の b にアクセス可能
A1 の c にアクセス可能
A1 の d には不可
パッケージ B
A1 にはアクセス不可
Figure: パッケージ クラスのメンバへのアクセス

継承

要約:
  • Curl 言語は、単一および多重継承をサポートしています。
  • クラスはスーパークラスからプライベート クラスのメンバを継承しません。
  • クラスは、スーパークラスからコンストラクタ、ファクトリー、クラス変数、クラス定数またはクラス プロシージャを継承しません。
  • final および sealed の修飾子は、クラスの継承方法に影響を与えます。
  • shared 修飾子により、共有状態のクラスを作成することができます。
クラスが他のクラスからメンバを継承するように指定することができます。他のクラスからメンバを継承するクラスは、継承元のクラスのサブクラスになります。他のクラスにメンバが継承されるクラスは、コードを継承するクラスのスーパークラスになります。Curl 言語は多重継承をサポートしています。つまり、クラスは複数のクラスからコードを継承することができます。
スーパークラス
サブクラス
クラス A
クラス B
(A を継承)
Figure: クラス継承
クラスからメンバを継承するためには、そのクラスへのアクセスが必要です。package アクセス属性のクラスからメンバを継承するコードは、スーパークラスと同じパッケージ内にある必要があります。
クラスはスーパークラスからすべてのメンバの名前を受け取りますが、private メンバはその例外です。したがって、プライベートメンバを除き、すべての継承されたクラス メンバの名前はサブクラスの名前空間内にあります。クラス メンバに名前を付けるときにこれを覚えておく必要があります。
クラスがメンバを継承する場合、結果として生成されるオブジェクトが必ずしもクラス メンバにアクセスできるとは限りません。オブジェクトがクラス メンバにアクセスできるかどうかを決めるのは、クラス メンバのアクセス属性とともにオブジェクトやメンバ定義が含まれたパッケージです。
クラスはスーパークラスから次のメンバを継承します。
次の特別なメンバは継承しません。
クラスを定義するには、クラスに追加するメンバを定義し、オーバーライドする継承メンバに対してコードを記述します。スーパークラスが使用していない継承クラス メンバは、クラス定義には表れません。
継承クラス メンバをオーバーライドするときに、メソッドまたはアクセッサの引数をオーバーライドすることができる場合があります。メソッドがリスト引数を受け取る場合は、オーバーライド メソッドも同じリスト引数を取る必要があります。また、メソッドが残余引数を受け取る場合も、オーバーライド メソッドも残余引数を受け取る必要があります。ただし、キーワード引数とその相対的な順序はオーバーライドできます。
コンストラクタとファクトリーはサブクラスに継承されません。各クラスは少なくとも 1 つのコンストラクタまたはファクトリーを持ち、それ自体でオブジェクトをインスタンス化します。つまり、新しいサブクラスを定義する場合は少なくとも 1 つのコンストラクタまたはファクトリーを記述する必要があります。このコンストラクタまたはファクトリーは、そのスーパークラスで対応するコンストラクタまたはファクトリーとは異なる引数を取ることができます。詳細は「コンストラクタとファクトリー」を参照してください。
クラスが同じ名前を持つ複数のメソッドを継承する場合、継承階層内で一番近くにあるメソッドだけが継承されます。メソッドの継承時に起こる競合をコンパイラがどのように解決するかについては、「メソッドの継承」を参照してください。
クラスの継承能力に影響を与えるいくつかの修飾子があります。final 修飾子はクラスがサブクラス化されないことを示します。sealed 修飾子は同じパッケージ内でのみサブクラス化できるクラスであることを示します。これらの修飾子を使用して、記述するクラスの継承について制限または制御を行なうことができます。

共有クラス

shared 修飾子は、複数回継承できるクラスであることを示します。たとえば Class D が 2 つのクラス Class B および Class C を継承するとします。Class B および Class C がどちらも Class A を継承する場合、Class Ashared クラスとして宣言する必要があります。
クラス A
クラス B
(A を継承)
クラス C
(A を継承)
クラス D
(B および C を継承)
Figure: 共有クラス
shared クラスの使用はパフォーマンスに影響します。shared フィールドを持つクラスへのアクセスは、共有されていないフィールドを持つクラスへのアクセスに比べて効率が悪くなります、これは、共有フィールドへのアクセスでは余分な回り道のステップが必要になるからです。また、スーパークラスのコンストラクタやファクトリーは継承されるたびに呼び出さなければなりません。つまり、 Class A を継承するクラスのインスタンスを 2 回作成した場合、Class A のコンストラクタは 2 回呼び出されることになります。クラスをデザインするときはこのことを念頭に置き、負担のかかる割り当て要求を回避するようにしてください。詳細については「コンストラクタとファクトリー」を参照してください。

Object クラス

要約:
  • Curl 言語はシングル ルートです。
  • Object クラスは Curl 言語のすべてのクラスのルートです。
  • すべてのクラスは暗黙的に Object クラスを継承します。
  • Object は抽象クラスです。
  • Object 型を任意のクラスを保持する変数として使用できます。
すべてのクラスは暗黙的に Object クラスを継承します。つまり Object クラスはすべてのクラスのスーパークラスになります。 Object は抽象クラスなので、 Object クラスのインスタンスは作成できません。
変数を Object 型として宣言した場合、その変数に任意のオブジェクトを代入することができます。これは、任意のオブジェクトを Object 型の変数に暗黙的に キャストすることになります。次に例を示します。
|| Assign an instance of HBox to "x".
let x:Object = {HBox "Hello"}
Object 型の変数にオブジェクトを代入すると、元のデータ型のクラス メンバにアクセスできなくなります (これはメンバが Object クラスに存在しないためです)。元のデータ型のクラス メンバにアクセスしようとすると、 RTE は構文エラーをスローします。
|| Use the HBox.add method to add contents to "x".
{x.add " World"}
--> 構文エラー:`Object にはメンバ 'add' がありません'
このような場合、 asa 演算子を使用してオブジェクトを適切なクラス メンバを持つ型に変換する必要があります。次のインタラクティブな例では、Object 型を使用してオブジェクトを代入し、元のクラス メンバにアクセスできるように変数を変換しています。

例: Object クラスの使用
{value
    || Assign an instance of HBox to "x".
    let x:Object = {HBox "Hello"}

    || Convert "x" to be of type HBox
    || Use the HBox.add method to add contents to "x".
    {(x asa HBox).add " World"}
    || Note that if you attempt to access the method
    || without converting "x", you generate an error.

    || Display "x"
    x
}

パラメータ化クラス

要約:
  • クラスはパラメータによって変化します。
  • パラメータにより、クラスのインスタンスを作成するときにクラスの定義情報を指定することができます。
  • 最も一般的な用法では、さまざまなデータ型を扱うクラスを作成するのに使用します。
クラス定義では 1 つまたは複数のパラメータを指定することができます。このようなクラスは パラメータ化クラス コンストラクタと呼ばれます。クラス定義でパラメータを使用して、特定のパラメータ化クラスを参照する場合にクラスを定義する情報を指定することができます。特定のパラメータ化クラスにおけるパラメータのバインドはコンパイル時に行われます。一般的に、パラメータ化クラスの作成は高度なプログラミングの領域に含まれます。
パラメータ化クラスには多くの使用方法があります。最も一般的な用法は異なるデータ型を扱えるクラスを作成することです。この場合、クラスの機能はすべてのデータ型に対して同じになります。パラメータ化クラスの例として特記に値するのが配列です。Array-of パラメータ化クラス コンストラクタは配列を実装します。配列の機能は、有効なすべてのデータ型に対して同じように提供されます。つまり、配列の要素へのアクセスや操作は、要素のデータ型にかかわらず同じ方法で行なうことができます。そのため、配列内で有効なそれぞれのデータ型に対応して個別のクラスを作成する必要はなく、パラメータ化クラス コンストラクタを 1 つ作成してすべてのデータ型を扱うことができます。パラメータ化クラス コンストラクタは実際にはクラスではなく、むしろクラスを作成するためのテンプレートといえます。
パラメータ化クラス コンストラクタを定義するには、クラス定義にパラメータを含めます。異なるデータ型のデータを扱えるパラメータ化クラスの場合、パラメータがデータ型を保持することになります。慣例により、このようなパラメータの名前は t ですが、任意の有効な識別子を使用できます。パラメータのデータ型は Type で、任意のデータ型を扱うことができます。Type クラスは任意のデータ型を表します。Array-of パラメータ化クラス コンストラクタの定義の例を次に示します。
{define-class public {Array-of t:Type}
  || body of class
}
もちろん、クラス本体は包括的な内容にして、t で可能な値をすべて扱うことができるようにする必要があります。
パラメータ化クラスに複数のパラメータを指定することができます。複数のパラメータがある場合は、カンマを使用してクラス定義内のパラメータ指定を区切ります。たとえば、次のクラス定義では 2 つのパラメータを指定し、それぞれがデータ型を保持します。
{define-class public {MyParameterizedTypeTemplate t1:Type, t2:Type}
  || body of class
}
特定のパラメータ化クラスを作成するには、パラメータのクラス名と値の両方を指定する必要があります。クラス名とパラメータは curl ブラケットで囲みます。たとえば、整数の Array-of クラスのインスタンスを作成するには次のように記述します。
let foo:{Array-of int} = {new {Array-of int}}
ここで、クラスのインスタンス作成に使用した new 式はオプションで、この場合は左 curl ブラケットを 2 回連続して使用しなくても済むように使用されています。クラスのインスタンスの作成の詳細については、「クラスのインスタンスの作成」を参照してください。複数のパラメータを指定する場合は、カンマを使用してパラメータを区切ります。次に例を示します。
let bar:{MyParameterizedTypeTemplate int, int} =
    {new {MyParameterizedTypeTemplate int, int}}

Value クラス

要約:
  • Value クラスは値によって渡されます。
  • define-value-classを使ってValue クラスを定義します。
  • Value クラスはObjectや他のいかなるクラスも継承しません。
  • Value クラスは定数フィールドしか持つことができません。
  • Value クラスは最適化されたメモリの使用を要する、小さなデータ型のみに使用します。
Value クラスは通常のクラスと似ていますがpass-by-value割り当て構造を使用します。つまり、変数に割り当てられたり関数やメソッドに引数として渡される場合は、Value クラスのインスタンスフィールドは新しいインスタンスとしてコピーされ、オリジナルのインスタンスへの参照として渡されることはありません。これによりValue クラスのインスタンスは可能なときには効果的にスタックに割り当てられることが許されます。さらに、通常のクラスはインスタンスの型を記録するためのメモリの余分な単語を要求しますが、Value クラスはフィールド自体が要する以上の余分なメモリを要求しません。従って、Value クラスはメモリの使用を最小化するデータ構造の実装に使用できます。Value クラスはdefine-value-classを使って定義されます。これはdefine-classと同様の構文を持ちますが、次のような要求された要素を持ちます。
構文:{define-value-class [access] final [modifier-list] ClassName
    members
}
where:
accessアクセス属性です。有効な属性はpubliclibrarypackageです。accessを指定しない場合、アクセス属性は規定のpackageとなります。詳細は「クラスへのアクセス」を参照してください。
modifier-list オプション修飾子のリストです。Value クラスはfinalとして明示的に宣言されなければならず、また継承を使うことはできないので、有効な修飾子はserializabledeprecatedです。詳細は「クラス修飾子の指定」を参照してください。
ClassName クラスの名前です。Value クラスの命名規則は通常のクラスの命名規則と同じです。
members クラス メンバです。通常のクラスをサポートするのと同じものですが、オプションは許されていません。さらに、Value クラスは最低ひとつのフィールドを宣言しなければならず、すべてのフィールドはconstantを宣言されなければなりません。
define-classと同様に、accesssmodifier-list、そして要求されたfinal 属性は、ClassNameの前の順位にも指定することができます。define-classと異なり、inherits 句はない場合があります。Value クラスは他のクラスから明示的に継承しないだけでなく、Objectからも暗黙的に継承しません。またValue クラスのインスタンスは、Object型の変数に割り当てられないこともあります。通常のクラスはValue クラスを継承しません。パラメータ化されたValue クラスが宣言されることがあります。例えばVector2d-of はパラメータ化されたValue クラスです。通常のクラスと違い、Value クラスのインスタンスにNULLが入ることは無いので、#ValueClassValueClass型の宣言に違いはありません。このため、すべてのValue クラスのインスタンスはそのValue クラスがimplicitコンストラクタや位置引数をとらないファクターを含む場合以外は、たとえ#形式で宣言されても、明示的に初期化されなければなりません。同様に、uninitialized-value-for-typeがValue クラス型に適用されているときに作り出すインスタンスは全フィールドがその型に初期化されない値にセットされます。これにより、呼び出し側はそれまで不可能だった値を作り出すことができます。Value クラスを作成する場合はこのことを覚えておいてください。Value クラスは通常のクラスよりフレキシブルでないため、データ型がメモリの最適化を要求し、サブクラス化が必要ないと開発者が知っている場合にのみ定義されなければなりません。Value クラスのオブジェクトのすべての内容は渡されるときにコピーされるので、インスタンスごとに少量のメモリ以上を要求するようなValue クラスを定義することは意味がありません。64ビット以上のストレージを要求するフィールドを持ったValue クラスは別途メモリの割り当てを要求することなしにany変数に格納することができません。従ってanyと使うことが予想される場合はValue クラスをこのサイズ内にしておくとよいでしょう。define-value-class構文により、開発者は独自のValue クラスを作り出すことができるようになりましたが、これはCurl APIの6.0バージョンより追加されました。しかし、Value クラスはそのかなり前からCurl APIの一部でした。たとえばKeycodePixelVector2d-ofなどのクラスはValue クラスです。

クラスのインスタンスの作成

要約:
  • クラスのインスタンスを作成する 2 つの方法があります。
  • new 式とクラス名を使用してオブジェクトを作成します。
  • クラスの名前のみ使用してオブジェクトを作成します。
  • トップレベル コードに可視クラスのインスタンスを含めると、RTE はそのオブジェクトを表示します。
クラスはデータ型の 1 つで、オブジェクトはクラスのインスタンスです。オブジェクトを作成するには 2 つの方法があります。
構文 (1):
{new class-specifier[.constructor-name][, argument-list]}
構文 (2):{class-specifier[.constructor-name] [argument-list]}
説明:
class-specifierクラスを指定します。一般的なクラスの class-specifier のフォームはClassName で、パラメータ化クラスでは class-specifier の次のフォームは{ClassName parameter-list} になります。
constructor-nameオプションのコンストラクタ名で、既定以外のコンストラクタを呼び出すときに必要です。
argument-listオブジェクトのインスタンス化に対する引数のリストです。引数を区切るにはカンマを使用します。
たとえば、次の各コード行は CommandButton クラスのインスタンスを作成します。
|| An instance of CommandButton (with no arguments specified).
{new CommandButton}                              || Syntax (1)
{CommandButton}                                  || Syntax (2)

|| An instance of CommandButton (with the label set).
{new CommandButton, label="Hello World"}         || Syntax (1)
{CommandButton label="Hello World"}              || Syntax (2)

|| An instance of CommandButton (with the label and background set).
{new CommandButton, label="Hello World", background="pink"} || Syntax (1)
{CommandButton label="Hello World", background="pink"}      || Syntax (2)
オプションの new 式の使用、および 2 つの構文によってカンマの使い方が異なる点に注意してください。同様に、次の各コード行は Array-of パラメータ化クラスのインスタンスを作成します。
|| An instance of Array-of (with no initial values).
{new {Array-of int}}                             || Syntax (1)
{{Array-of int}}                                 || Syntax (2)

|| An instance of Array-of (with initial values).
{new {Array-of int}, 1, 2, 3}                    || Syntax (1)
{{Array-of int} 1, 2, 3}                         || Syntax (2)
変数にオブジェクトを代入することができます。変数には互換性のある型を指定する必要があります。たとえば、次のコードは CommandButton 型の変数を宣言し、変数に CommandButton クラスのインスタンスを代入します。
|| Declare a variable of type CommandButton.
let var:CommandButton

|| Assign an instance of the CommandButton class to the variable.
set var = {CommandButton}
もちろん、次のように 1 つのステートメントで変数を定義して初期化することもできます。
|| Declare a variable of type CommandButton and
|| initialize it with an instance of the
|| CommandButton class.
let var:CommandButton = {CommandButton}
クラスのインスタンスを作成すると、RTE はそのクラスのコンストラクタを呼び出します。コンストラクタはクラスのインスタンスを初期化します。クラスにファクトリーがある場合は代わりにファクトリーを呼び出します。ファクトリーを使用してオブジェクトの既定の初期化をオーバーライドすることができます。これらの特別なメソッドの詳細については「コンストラクタ」および 「ファクトリー」を参照してください。
コンストラクタおよびファクトリーでは引数を取ることができます。これは、クラスのインスタンスを作成するときに引数の指定が必要になる場合があることを意味します。

変数を持つオブジェクトと持たないオブジェクトの使用

Curl 言語には、変数にオブジェクトを代入せずにオブジェクトを作成して使用できるというユニークな能力を備えています。この機能を活かして複数のオブジェクトをすばやく作成して表示することができます。トップレベルのコードに可視クラスのインスタンスを含めるだけで、RTE はこのようなオブジェクトを表示することができます。ただし、これは Visual のサブクラスなどのビジュアル表現機能を持つクラスに限られます。
変数を使用しない場合、オブジェクトをインスタンス化した後はそのプロパティにアクセスできなくなります。ただし多くのアプリケーションでは、組み込みのグラフィック システムの各機能を使用すればプログラミングに時間を費やさずにアプリケーションを構築できる場合が多いので、このようなアクセスは必要がないかもしれません。
次の例では、変数を使用せずに水平方向のボックス ( HBox オブジェクト) を作成してボタンを 2 つ配置しています。( HBoxCommandButton は両方とも Visual サブクラスであることに注意してください。)

例: 変数のないオブジェクトの使用
{HBox
    {CommandButton},
    {CommandButton}
}
次の例では、変数 h を使用して add メソッドを呼び出して同じ結果を生成しています。ここで大切なのは、変数で表されるオブジェクトの場合はそのプロパティへのアクセスや変更が可能ですが、変数に代入されていないオブジェクトの場合は同じことができないという点です。

例: オブジェクトへのアクセスに変数を使用
{value
    let h:HBox = {HBox}
    let b:CommandButton = {CommandButton}

    {h.add b}
    {h.add {CommandButton}}
    h
}