フィールドとアクセッサ

このセクションでは、フィールドとアクセッサについて説明します。

フィールド

クラスのオブジェクトは、データと関連コードで構成されます。各オブジェクトに関連するデータはフィールドに格納されます。クラスの各オブジェクト内のフィールドを定義するには、クラス定義内で次の構文を使用します。
構文:[{]field [access] [modifier-list] field-name[:field-type] [= initial-value][}]
説明:
accessアクセス属性です。有効な属性には publiclibraryprotectedpackageprivate、さらにこれらの -get-set 変形 (variant) があります。access を指定しない場合、アクセス属性は既定で package になります。詳細は、「フィールド アクセス属性の指定」を参照してください。
modifier-listオプションの修飾子です。フィールドの有効な修飾子は constantweak および deprecated です。詳細は、「フィールド修飾子の指定」を参照してください。
field-nameフィールドの名前です。Curl® 言語では、フィールドの命名規則でフィールド名には小文字のみ使用します。フィールド名に複数の単語が含まれる場合は、ハイフンで区切ります。
field-typeフィールドのデータ型です。データ型を指定しない場合、Curl® 実行環境 (RTE) は any 型を使用します。field-type の 1 つまたは initial-value の指定が必要です。
initial-valueフィールドの初期値です。初期値はオプションです。初期値を指定しない場合、field-type に既定値が代入されます。field-type の 1 つまたは initial-value の指定が必要です。
たとえば、次のコードでは private int フィールドをフィールド名 _my-field と定義し、初期値は 9 に設定します。
|| A private int _my-field that is initialized to 9.
field private _my-field:int = 9
フィールドはサブクラスによって継承されます。クラス A にデータフィールド my-field があり、クラス B がクラス A を継承すると、B 型のすべてのオブジェクト b には A 型オブジェクトの関連フィールド my-field が含まれます。スーパークラス フィールドのアクセス属性は、そのフィールドに b.my-field として直接アクセス可能かどうかを決定します。ただしクラス A 内のフィールドがプライベートと宣言された場合はフィールドに直接アクセスすることはできず、アクセッサまたはメソッドを介して間接的にのみアクセスできます。(この場合、スーパークラスのプライベート フィールドと同じ名前の新規フィールドを、競合せずにサブクラスに作成することができます。)

フィールド アクセス属性の指定

要約:
  • public は、すべてのコードがフィールドにアクセスできることを意味します。
  • library は、同じライブラリ内のコードだけがフィールドにアクセスできることを意味します。
  • package は、同じパッケージ内のコードのみがフィールドにアクセスできることを意味します。
  • protected は、同じパッケージ内のコードまたはサブクラス内のコードのみがフィールドにアクセスできることを意味します。
  • private は、同じクラス内のコードのみがフィールドにアクセスできることを意味します。
  • 既定値は package です。
  • private を指定して、フィールドに個別のアクセッサを指定するのが一般的です。
  • -get-set 変形は、読み取りや書き込み用に異なるアクセスを設定するために使用できます。
アクセス属性は、フィールドにアクセスできるコードを示すものです。アクセス属性は保護属性とも呼ばれます。コードがフィールドにアクセスするには、まずフィールドを格納するクラスへのアクセスが必要です。アクセス属性の指定はオプションです。フィールドについては、次の 4 つの基本アクセス属性があります。
既定のアクセス属性は package です。アクセス属性を指定しない場合、package アクセス属性が使用されます。
すべてのコードをフィールド アクセス可能にするには public を使用します。フィールドと同じパッケージにあるコードのみアクセス可能にするには package を使用します。フィールドと同じパッケージ、またはサブクラスにあるコードのみアクセス可能にするには protected を使用します。アクセス属性に関する詳細の情報に関しては、library を御覧下さい。
同じクラス定義内のコードのみアクセス可能にするには private を使用します。プライベート フィールドは、定義されたクラス外ではアクセスできません。アクセッサを個別に使用して、値を取得または設定することもできます。(アクセッサの例については、「アクセッサ」のセクションを参照してください。)
注意: クラス内部以外から直接アクセスできないことを明確にするために、プライベート フィールドの名前を下線で開始するのが一般的な規則です。
|| A private field that is initialized to 9.
field private _my-field:int = 9
基本アクセス属性には、それぞれサフィックス -get-set を使用する変形があります。これらを使用して、フィールド値の読み取りや書き込み用に異なるアクセス レベルを定義します。たとえば、次のコードは my-field というフィールドについて、my-field 値の読み取りはすべてのコードで可能ですが、値の設定は同じクラス内のコードでのみ可能であるように指定しています。
|| A publicly gettable but only privately settable
|| field with an initial value of 9.
field public-get private-set my-field:int = 9
-get および -set の変形は、基本アクセス属性と混用しないでください。(たとえば、publicprivate-set と同時に使用できません。)-get または -set 属性のどちらかを省略した場合、既定によりそれぞれ package-get または package-set になります。
constant フィールドについては、初期化した後で値を設定できないので、-set の特別アクセス属性を使用する必要はないことに注意してください。
クラス private のフィールドを作成し、フィールド値の読み取りやフィールドへの新規の値の書き込みに使用するアクセッサを作成するのが一般的です。これにより、アクセッサはフィールドの読み取りまたは書き込みに適したアクセス属性を持つことになります。アクセッサの使用によって、フィールドのアクセス、データ検証の許可、不正アクセスの制限などに対してカスタム コードを提供することができます。

フィールド修飾子の指定

要約:
  • constant は、初期化の後で常に同じオブジェクトが格納されるフィールドを意味します。
  • weak は、ガーベッジ コレクションに使用可能なフィールドを意味します。
修飾子を使用してフィールドのコンパイル方法を変更できます。Curl 言語ではフィールドについて、constantweak 修飾子をサポートします。
constant フィールドは、初期化された後は常に同じオブジェクトまたは値を参照します。定数フィールドへの代入は、そのクラスのコンストラクタ外では行えません。定数フィールドを初期化するには、初期値を指定するか、コンストラクタ内で代入するかのどちらかの方法が必要です。 オブジェクトが生成されてから、フィールド値が変更されないようにするには、constant として宣言する必要があります。
weak フィールドは、ガーベッジ コレクションで使用するフィールドです。詳細については、「メモリの管理:Weak ポインタ」を参照してください。

アクセッサ

要約:
  • ゲッターは特別なメソッドで、次の性質があります。
    • 引数をとりません。
    • 値を1つリターンします。
    • フィールド検索と似たシンタックスです。
  • セッターは特別なメソッドで、次の性質があります
    • 引数を1つとります。
    • 宣言されたリターンタイプがありません。
    • フィールド値を設定するのと似たシンタックスです。
アクセッサは特殊なタイプのメソッドで、フィールド アクセスの構文を模倣しますが、任意のコードを実行することができます。これらを使用してクラス メンバを実装します。クラス メンバはフィールドのように読み取られますが、実際には他のクラス メンバの値から計算されるか、設定時に他のクラス メンバの値を更新するか、あるいは設定時にデータ値を自動的に検証します。アクセッサはまた、メソッドと同様にサブクラス内でオーバーライドされて異なる動作を実行することができます。には次の 2 つのタイプがあります。
ゲッターの構文は次のとおりです。
構文:{getter [access] [modifier-list] {accessor-name}:return-type
    code
}
説明:
accessアクセス属性です。有効な属性は publiclibraryprotectedpackage および privateです。access を指定しない場合、アクセス属性は既定で package になります。アクセッサは通常 public です。詳細は、「メソッド アクセス属性の指定」を参照してください。
modifier-listオプションの修飾子のリストです。ゲッターの有効な修飾子は abstractfinalsealedopeninline および deprecated です。複数の修飾子を指定する場合は、各修飾子を空白文字で区切ります。詳細は、「アクセッサ修飾子の指定」を参照してください。
accessor-nameアクセッサの名前です。Curl 言語では、命名規則で小文字のみ使用します。アクセッサ名に複数の単語が含まれる場合は、ハイフンで区切ります。ゲッターとセッターに同じ名前を付けることもできます。
return-typesアクセッサの戻り値のデータ型です。ゲッターは 1 つの値のみ返します。
codeアクセッサのコードです。コードには変数と式の定義を含めることができます。値を返す return 式をコードに含める必要があります。
たとえば、次のコードはフィールド lengthdistance、および area と言うゲッターが含まれたシンプルな Rectangle クラスを示します。area クラス メンバはフィールドと同様に読み込み可能ですが、widthlength フィールドに基づいてダイナミックに計算されます。

{define-class public MyRectangle
  
  || Length of rectangle
  field public length:Distance
  
  || Width of rectangle
  field public width:Distance
  
  || Compute area based on length and width
  {getter public {area}:Area
    {return self.length * self.width}
  }
}
{let r:MyRectangle = 
    {MyRectangle}
}
{set r.length = 10cm}
{set r.width = 5cm}
{value r.area}
セッターの構文は次のとおりです。
構文:{setter [access] [modifier] {accessor-name arg-name:arg-type}
    code
}
説明:
access上記のゲッターの項目での説明と同様です。
modifier-list上記のゲッターの項目での説明と同様です。
accessor-name上記のゲッターの項目での説明と同様です。
arg-nameセッターの引数の名前です。
arg-typeセッターの引数のデータ型です。
codeセッターのコードです。コードには変数と式の定義を含めることができます。
たとえば、次のコードは _my-field というフィールドと my-field というゲッターとセッターを示します。このフィールドはプライベートなので、クラス内のコードのみがフィールドにアクセスできます。セッターはパブリックなので、すべてのコードがセッターにアクセスできます。セッターは次の 1 つの引数であるフィールドの設定値を取ります。セッターは、値をプライベート フィールドに代入する前にそれを検証します。引数の名前はオプションで、フィールド名と同じである必要はありません。セッターは値を返さないので、戻り値のデータ型は指定しません。
|| A private int field that is initialized to 9.
field private _my-field:int = 9

|| A getter for my-field.
{getter public {my-field}:int
    {return self._my-field}
}

|| A setter for my-field that validates the value.
{setter public {my-field value:int}
    {if value == 42 then
        {error "my-field may not be set to 42"}
    }
    set self._my-field = value
}
注意: 通常、セッターの名前には関連するゲッターと同じ名前を付けます。これにより、クラスのユーザーは my-field をデータ フィールドと同様に使いやすい単一の属性として、高位レベルで参照することができます。
コード内では、ゲッターまたはセッターを明示的に呼び出しません。代わりに、ゲッターとセッターの名前をフィールドの名前として扱います。実行時にコード内でゲッターまたはセッターの名前が検出されると、ゲッター、セッターとして呼び出されます。たとえば、上記のコードでは my-field の読み取り時に my-field ゲッターが呼び出されます。同様に my-field の値を設定するとき my-field セッターが呼び出されます。
ゲッターとセッターを暗黙的に呼び出す例について、次のインタラクティブな例を参照してください。

例: ゲッターとセッターの使用
|| A class.
{define-class public Person

  || A private field
  field private _age:int = 0

  || Get someone's age.
  {getter public {age}:int
    {return self._age}
  }

  || Set someone's age.
  {setter public {age years:int}
    {if years < 0 then
        {error "Age in years must be >= 0."}
    }
    set self._age = years
  }
}

|| Create an object of type Person
{let child:Person = {Person}}

|| Use the "age" getter
{value child.age}

|| Use the "age" setter
{set child.age = 7}
       

アクセッサのアクセス属性の指定

要約:
  • ゲッター、セッターは通常 public です。
  • public は、すべてのコードがゲッターまたはセッターにアクセス可能であることを意味します。
  • 既定値は packageです。
  • package は、同じパッケージ内のコードのみがゲッターまたはセッターにアクセス可能であることを意味します。
  • protectedは、同じパッケージまたはサブクラスのコードが、ゲッターまたはセッターにアクセスすることができるということを意味します。
  • private は、同じクラス定義の中のコードのみがゲッターまたはセッターにアクセス可能であることを意味します。
アクセス属性は、ゲッターまたはセッターにアクセス可能なコードを定義します。全てのゲッターと一部または全てのセッターをクラス public に指定して、すべてのコードについてゲッターまたはセッターへのアクセスを確保します。しかし、この場合、ゲッター、セッターを格納するクラスにコードがアクセス可能であることが前提条件となります。
アクセス属性の指定はオプションです。既定のアクセス属性は package です。アクセス属性を指定しない場合、package アクセス属性が使用されます。package アクセス属性は、ゲッター、セッターと同じパッケージ内にあるコードへのアクセスを制限する役割を果たします。 セッターの属性を、同じ名称の public ゲッターと共に指定し、パッケージ外で読み専用のプロパティーを作成することも可能です。
ゲッター、セッターについての有効なアクセス属性は一覧を次に表示します。
ゲッター、セッターと同じパッケージ内にあるコードのみのアクセスを許可する場合、またはパッケージとは無関係にサブクラス内にあるコードのみのアクセスを許可する場合は protected を使用します。ゲッター、セッターと同じクラス内にあるコードのアクセスを制限する場合は、private を使用します。プライベートのゲッターとセッターは、それらが定義されているクラス内部でのみアクセス可能です。サブクラスは、プライベートのゲッター、セッターを継承しません。このため、スーパークラス内では private ゲッター、セッターと同じ名前のゲッター、セッターを持つことができます。同じパッケージ内のコードだけにアクセッサ使用を制限する場合は package を使用し、無制限のアクセスを許可する場合は public を使用します。
次の例はアクセッサを使用し、-get および -get のアクセス属性の変形を示しています。 サブクラス ChildPerson から継承しているセッター age をオーバーライドすることに留意してください。

例: アクセッサの定義
|| Define the superclass Person
{define-class public Person

  || A private field
  field private _age:int = 0

  || Get a Person's age.
  {getter public {age}:int
    {return self._age}
  }

  || Set a Person's age.
  {setter public {age years:int}
    {if years < 0 then
        {error "Age in years must be >= 0."}
    }
    set self._age = years
  }
}
|| Define a subclass, Child
{define-class public Child {inherits Person}
  field public-get private-set age-in-months:int = 0

  || Require a Child to be under 21,
  || by overriding the inherited age setter
  {setter public {age years:int}
    {if years >= 21 then
        {error "Age in years must be < 21."}
     else
        || invoke parent class setter
        set super.age = years
        || use private setter from this class
        set self.age-in-months = years * 12
    }
  }
}

{let child:Child = {Child}}

|| Use setter from Child class; also try setting age to 22!
{set child.age = 3}

|| Use getter from Person class to
How many years old is your child? ... {value child.age}

|| Uses public getter from Child class
How many months old is your child? ... {value child.age-in-months}
       

アクセッサ修飾子の指定

要約:
アクセッサは他のメソッドと同じ修飾子を使用します。
  • abstract は抽象ゲッター、セッターを意味します。
  • inline は、コンパイラに対して、ゲッター、セッターの呼び出しを実際のゲッター、セッターのコードで置換するように指示します。
  • final は、このゲッター、セッターをサブクラスがオーバーライドできないことを意味します。
  • sealed は、このゲッター、セッターがこのクラスの同じパッケージ内に格納されていない限り、サブクラスがオーバーライドできないことを意味します。
  • open は、このゲッター、セッターをどのサブクラスでもオーバーライドできることを意味します。
  • deprecated は、このゲッター、セッターは将来のバージョンで削除される可能性があり、新規コードでの使用を回避することを意味します。
ゲッターとセッターにおいての他のメソッドに関しては、Curl 言語では次の修飾子をサポートします。
抽象ゲッター、セッターを示すには abstract を使用します。抽象ゲッターまたはセッターは、定義されたクラス内で実装されないゲッターまたはセッターです。非抽象サブクラス内のゲッター、セッターは、コードを実装する必要があります。抽象ゲッター、セッターは、さまざまな実装の汎用インターフェイスの役割を果たします。抽象ゲッター、セッターにはコード本体はありません。次の例には抽象セッターが含まれています。
{setter public abstract {my-field _my-field:int}:void}
注意: 抽象ゲッター、セッターは、抽象クラス内のみで定義できます。
inline の使用で、コンパイラに、実行時にゲッター、セッターの呼び出しを実際のゲッター、セッターのコードに置き換えるように指定することが出来ます。場合によっては、インライン ゲッターまたはセッターを使用してコードの実行タイムを短縮できることがあります。これは通常、多数の異なる位置から呼び出されない小さなゲッター、セッターを使用する場合に起こります。inline が存在する場合、ゲッター、セッターのインライン置換が実行時に試行されます。ただし、インライン置換を実行する前に、インライン置換で最適化されたコードが生成されるかどうかが判定されます。インライン置換で最適化されたコードが生成されないと判定された場合、置換は実行されません。
最終ゲッター、セッターを示すには final を使用します。最終ゲッター、セッターはサブクラスでオーバーライドできません。サブクラスがゲッター、セッターをオーバーライドする必要があるかどうかの判断は難しいところです。ゲッター、セッターのオーバーライドがないことが明らかな場合は、必ず final 修飾子を使用します。final 修飾子を使うと、よりコンパクトで高速のコードが生成されます。private アクセスのゲッター、セッターはクラス外から見えないので、すべて暗黙的に final になることに注意してください。
シールド ゲッター、セッターを示すには sealed を使用します。他のパッケージのサブクラスは、シールド ゲッター、セッターをオーバーライドできません。他のパッケージのサブクラスがゲッター、セッターをオーバーライドする必要があるかどうかの判断は難しいところです。ゲッター、セッターが他のパッケージのクラスでオーバーライドされないことが明らかな場合、必ず sealed 修飾子を使用します。sealed 修飾子を使うと、よりコンパクトで高速のコードが生成されます。package アクセスのメソッドはすべて、そのパッケージ外から見えないので、オープン宣言できず、暗黙的にシールドになることに注意してください。
ゲッター、セッターが任意のサブクラス内でオーバーライド可能であるよう指定するには、open を使用します。これは、publiclibraryまたは protected アクセスのすべてのゲッター、セッターについて、既定のオーバーライド属性になります。
注意: コンパイラ ディレクティブ allow-implicit-open? = false が適用されている場合 (コンパイラ ディレクティブ stringent? = true で暗黙的に適用)、次のオーバーライド属性、opensealed または final を、それぞれ定義されるゲッター、セッター(およびクラスとその他のメソッド) について指定する必要があります。詳細は、「コンパイラ ディレクティブ」の章を参照してください。
将来削除される可能性があり、新規コードでの使用を回避するゲッター、セッターを示すには deprecated を使用します。

最小アクセッサ

private フィールドへのアクセスを制御するだけの目的のアクセッサを定義する場合もあります。 次の例では、ゲッターとセッターはフィールドの値を読み書きするのみで、 コントロール フローやコンピュテーションは可能ではありません。

例: 最小アクセッサ
{define-class public Person

  || A private field
  field private _age:int = 0

  || a public getter for a private field
  {getter public {age}:int
    {return self._age}
  }

  || a protected setter for a private field
  {setter protected {age years:int}
    set self._age = years
  }
}
前例のコードでは、サブクラスによって継承されるアクセッサが作成されます。 クラス内のフィールド アクセスを制御する必要がある場合は、 -get または -set の変形を使用します。 次の例では、フィールド age への、 読み込み/書き込みにおける別のアクセス方法を示します。 サブクラスによって継承およびオーバーライドされるアクセッサは作成されません。 詳細は、「フィールド アクセス属性の指定」を参照してください。

例: 最小アクセッサ
{define-class public Person

  || A field that with a public getter and a
  || protected setter
  field public-get protected-set age:int = 0
}