きくらげ観察日記

好きなことを、適当に。

Gaucheでクラスの作成

どうやらGaucheにもクラスは存在するようで、継承やアクセサの設定など、基本的なクラスに関する操作は行うことができます。

クラスの定義

(define-class <animal> ; クラス名
  ()                   ; 親クラスのリスト
  ())                  ; スロット一覧

(define-class <person> (<animal>)
  ((name)
   (age)))

インスタンスの生成

(define taro (make <person>))

スロットへのアクセス

(slot-set! taro 'name "Taro")
(slot-set! taro 'age 15)

(slot-ref taro 'name) ; => "Taro"
(slot-ref taro 'age)  ; => 15

アクセサの生成

(define-class <person> (<animal>)
  ((name :accessor name)
   (age :accessor age)))

(define taro (make <person>))

(set! (name taro) "Taro")
(set! (age taro) 15)

(name taro) ; => "Taro"
(age taro)  ; => 15

このときname, ageはジェネリック関数となるため、他のクラスのスロットへのアクセサと名前が重複していても構いません。
また、読み込み専用のアクセサは:getter, 書き込み専用のアクセサは:setterで作ることができます。

初期化時にスロットの値を指定

(define-class <person> (<animal>)
  ((name :accessor name :init-keyword :name)
   (age :accessor age :init-keyword :age)))

(define taro (make <person> :name "Taro" :age 15))

(name taro) ; => "Taro"
(age taro)  ; => 15

デフォルト値の指定

(define-class <person> (<animal>)
  ((name :accessor name :init-keyword :name)
   (age :accessor age :init-keyword :age)
   (country :accessor country :init-keyword :country :init-value "Japan")
   (sex :accessor sex
        :init-keyword :sex
        :init-form (error "sex must be specified"))))

(define taro (make <person> :name "Taro" :age 15 :sex 'male))

(country taro) ; => "Japan"

(define jiro (make <person> :name "Jiro" :age 12)) ; => ERROR: sex must be specified

init-value, init-formを用いると、スロットのデフォルト値を設定することができます。init-valueはクラス生成時に値が評価され、init-formはインスタンス生成時に値が評価されます。
Gaucheのクラスでは初期化時に特定のスロットの値の指定を必須にすることができないので、そのようにしたい場合は上の例のように:init-formにエラーや例外などを指定するとよいかもしれません。

参考

define-classのオプション一覧などはこちらを参照してください。
Gauche ユーザリファレンス: 7.2 クラス