Schemeは動的な強い型付けの言語です。つまり、全ての値は 実行時に自分の型を知っていて、その型が値に適用できる操作を決定します。
Gaucheでは、クラスによって型を記述します。クラス自身もオブジェクトであり、 実行時に取り扱うことができます。新たなクラスを作成することで、 既存の型とは異なるユーザ定義型を使うことができます。
R6RSから、Schemeにも新しい型を定義する機能が標準で備わりました。
define-record-type
を使います。Gaucheでも、
gauche.record
モジュールを使うことでレコード型を定義できます。
レコード型を参照してください。内部的にはレコード型は
クラスで実装されています。
この節ではもっとも基本的な型システムへのインタフェースを説明します。 新たなクラスを定義し、そのインスタンスを作る方法については オブジェクトシステムを参照してください。
あらかじめ定義されているクラスはグローバル変数に束縛されています。Gaucheでの
慣習として、クラスを格納している変数は<string>
のように
<
と>
で囲まれた名前を持ちます。
(この<
や>
は文法的には何ら特別な意味を持ちません。
普通に変数名として使える文字です)。
組み込みの型に対応するクラスについては、この章の中で順に紹介してゆきます。
まずは次のいくつかのクラスから始めましょう。
全ての型のスーパータイプを表現するクラスです。
つまり、どんなクラスX
に対しても(subtype? X <top>)
は#t
であり、
どんなオブジェクトx
に対しても(is-a? x <top>)
は#t
です。
全ての型のサブタイプを表現するクラスです。
どんなクラスX
に対しても(subtype? <bottom> X)
は#t
であり、
どんなオブジェクトx
に対しても(is-a? x <bottom>)
は#f
です。
<bottom>
型のインスタンスは存在しません。
註: <bottom>
は全ての型のサブタイプですが、そのクラス順位リスト
(class precedence list, CPL)には<bottom>
と<top>
以外のクラスは含まれていません。全ての型を線形に並べることは常に可能である
とは限らず、まだそうであったとしても新たなクラスの定義や既存のクラスの
再定義のたびに<bottom>
のCPLを検査してアップデートすることは
高くつくでしょう。subtype?
やis-a?
といった手続きは
<bottom>
を特別扱いしています。
<bottom>
の使いどころのひとつは、applicable?
手続きです。
Procedure class and applicabilityを参照のこと。
このクラスは、ユーザ定義されたクラスのスーパータイプを表現するクラスです。
objのクラスを返します。
(class-of 3) ⇒ #<class <integer>> (class-of "foo") ⇒ #<class <string>> (class-of <integer>) ⇒ #<class <class>>
註: Gaucheでは、ユーザ定義クラスを再定義することができます。
新たな定義でインスタンスの構造が変更された場合、以前のクラスから作られた
インスタンスにclass-of
を適用すると、インスタンスが新しいクラスに
適合するようにアップデートされます。詳しくはクラスの再定義を参照して
ください。インスタンスアップデートを避けるにはcurrent-class-of
を
使います(インスタンスへのアクセス参照)。
objがclassのインスタンスであるか、classのサブクラスの インスタンスである場合に、真を返します。
(is-a? 3 <integer>) ⇒ #t (is-a? 3 <real>) ⇒ #t (is-a? 5+3i <real>) ⇒ #f (is-a? :foo <symbol>) ⇒ #f
註:objのクラスが再定義されていた場合、is-a?
はインスタンスアップデートを
トリガします。クラスの再定義を参照してください。
クラスsubがクラスsuperのサブクラスであれば(subとsuperが
同じである場合も含め)#t
を、そうでなければ#f
を返します。
(subtype?
という名前はCommon Lispのsubtypep
から来ています)。