Gauche の拡張ライブラリでクラスを定義する

Gauche の拡張ライブラリで、自分でクラスを定義する方法、というよりメモとしてのテンプレート。正しい手順か不明だけど、とりあえず動く。

安直だけど、"clos" という名前の拡張ライブラリを書くとして、Scheme で書くと次のような定義になるようにする。

(define-class <person> ()
  ((name :init-value "Anonymous")
   (age  :init-value 20)))

拡張ライブラリのヘッダファイル clos.h の宣言。

typedef struct ScmPersonRec {
    SCM_HEADER;
    ScmObj name;
    int age;
} ScmPerson;

SCM_CLASS_DECL(Scm_PersonClass);
#define SCM_CLASS_PERSON	(&Scm_PersonClass)
#define SCM_PERSON(obj)		((ScmPerson*)obj)
#define SCM_PERSON_P(obj)	SCM_XTYPEP(obj, &Scm_PersonClass)

// ScmObj Scm_MakePerson(void);

構造体を使ってクラスのスロットを用意。さらに、マクロ。命名規則gauche.h で使われているものを参考にした。最後のコメントアウトされている Scm_MakePerson は、gosh 側で を使うときには必要なく、拡張ライブラリ内で を作りたいときに使うので、今回は省略。

次に clos.c。

static ScmObj person_allocate(ScmClass *klass, ScmObj initargs);

SCM_DEFINE_BUILTIN_CLASS(Scm_PersonClass,
			 NULL, NULL, NULL,
			 person_allocate,
			 NULL);

static ScmObj person_allocate(ScmClass *klass, ScmObj initargs)
{
    ScmPerson *p = SCM_NEW(ScmPerson);
    SCM_SET_CLASS(p, SCM_CLASS_PERSON);
    p->name = SCM_MAKE_STR("Anonymous");
    p->age = 20;
    return SCM_OBJ(p);
}

static ScmObj person_name(ScmPerson *p)
{
    return p->name;
}

static ScmObj person_age(ScmPerson *p)
{
    return SCM_MAKE_INT(p->age);
}

static void set_person_name(ScmPerson *p, ScmObj val) {
    if (SCM_STRINGP(val)) {
	p->name = val;
    } else {
	Scm_Error("slot name  must be a string.?n");
    }
}

static ScmClassStaticSlotSpec person_slots[] = {
    SCM_CLASS_SLOT_SPEC("name", person_name, set_person_name),
    SCM_CLASS_SLOT_SPEC("age", person_age, NULL),
    { NULL }
};

クラスのアロケーションに使われる関数が person_allocate。スロットの初期値もここでセットしておく。 クラスのスロットを slot-ref を使ってアクセスしたい場合は、getter / setter 用の関数も用意する必要がある。 をインクルードする必要あり。今回は、name スロットについては両方用意してみた。age は getter のみだが、int を ScmObj でくるんで返す。スロットを完全に隠蔽するなら、必要ない。最後に、モジュールの初期化関数内で、Scm_InitStaticClass を使ってクラスを初期化(登録?)する。

ScmObj Scm_Init_clos(void)
{
    ScmModule *mod;

    /* Register this DSO to Gauche */
    SCM_INIT_EXTENSION(clos);

    /* Create the module if it doesn't exist yet. */
    mod = SCM_MODULE(SCM_FIND_MODULE("clos", TRUE));

    Scm_InitStaticClass(SCM_CLASS_PERSON, "<person>", mod, person_slots, 0);

    /* Register stub-generated procedures */
    Scm_Init_closlib(mod);
}

今回 closlib.stub はノータッチ。clos.scm で シンボルをエクスポートして終わり。

gosh からテスト。

gosh> (use clos)
#<undef>
gosh> (d <person>)
#<class <person>> is an instance of class <class>
slots:
  name      : <person>
  cpl       : (#<class <person>> #<class <top>>)
  direct-supers: (#<class <top>>)
  accessors : ((age . #<slot-accessor <person>.age native :age>) (name . #
  slots     : ((name :allocation :builtin :slot-accessor #<slot-accessor <
  direct-slots: ((name :allocation :builtin :slot-accessor #<slot-accessor <
  num-instance-slots: 0
  direct-subclasses: ()
  direct-methods: ()
  initargs  : ()
  defined-modules: ()
  redefined : #f
  category  : builtin
gosh> (define *p* (make <person>))
*p*
gosh> (slot-ref *p* 'name)
"Anonymous"
gosh> (set! (slot-ref *p* 'name) "tomapd")
#<undef>
gosh> (slot-ref *p* 'name)
"tomapd"
gosh> (set! (slot-ref *p* 'age) 0)
*** ERROR: slot age of class #<class <person>> is read-only
Stack Trace:
_______________________________________
  0  (set! (slot-ref *p* 'age) 0)
        At line 7 of "(stdin)"
  1  (set! (slot-ref *p* 'age) 0)
        At line 7 of "(stdin)"

動いた。

gosh> (d (make <person> :name "tomapd" :age 24))
#<<person> 0x696ec0> is an instance of class <person>
slots:
  name      : "tomapd"
  age       : 20

setter を定義したスロットについては、:init-keyword としても使えるみたい。

SLIME + utf-8 の件

今まで Common Lisp では計算ばっかりしていたので、扱うのは ASCII 文字ばかだったため気付かずに幸せに暮らしていたのだが、昨日ちょっと気が向いてテキストファイルを読み込んで集計するプログラムを作ってみようと思った。UTF-8 エンコーディングSBCL が対応しており、Emacs (CarbonEmacs) も UTF-8 を使っていた。問題は起こらないと思っていた。

ところが、SBCL w/ SLIME で UTF-8 エンコードされた日本語ファイルを読み込んだところ、無限ループに陥るような挙動を示した。コンソールで SLIME を経由せずに SBCL から読み込む場合は問題ない。これは SLIME のバグだ、と思い込み、メーリングリストに訴えた。
[slime-devel] Slime w/ SBCL 0.9.11 (MacOSX/PPC): no response after reading utf-8/euc-jp files
軽率だった。返事をもらった。
[slime-devel] Slime w/ SBCL 0.9.11 (MacOSX/PPC): no response after reading utf-8/euc-jp files
ちゃんと SLIME の設定で UTF-8 を指定したのか、と。

(setq slime-lisp-implementations
      '((sbcl ("sbcl") :coding-system utf-8-unix)
	(cmucl ("cmucl") :coding-system iso-latin-1-unix)))

してませんでした。検索したらマニュアルにも書いてあった。Google 先生に聞いてからリストにメール出すべきだと改めて思った。

SBCL threads on Intel Mac

CL 処理系 SBCLMac OS X / Intel におけるスレッドサポートに関する議論メモ(@sbcl-devl)。

2006-03-21 Threads and Lutexes on Mac OS X for Intel Status Update より:

Nathan Froyd and I have been working on getting threads up and running on Mac OS X for Intel. Back in November or so, Nathan originally proposed the concept of a lutex, or a lisp mutex lock, that would be API compatible with the current linux futex-based locking code.

Nothan Froyd と Cyrus Harmon の二人が Darwin/x86 上の SBCL でスレッドを動作させようと試みている。Cyrus Harmon は、www.cyrusharmon.org Coming Soon! の人。メールの技術的な中身はついていけないのだが、最後のまとめとしては、

Back to good news, we can rebuild #+(and sb-thread sb-lutex) with itself and we pass all 14 contrib tests. So things are looking good, but there is still more work to do.

うまくいきそうだと。さらに、たぶん今回あらたに開発した lutex (lisp mutex lock) による互換性の向上からだと思うが、

If this is successful it also suggests that threads on PPC/darwin might be feasible as well.

PPC 上でもスレッドがいけるかもしれないと。期待して待ちたい。

SLIME 2.0 Released

Emacs 上で動作する Common Lisp (CL) の開発環境、SLIME が 2.0 としてリリースされた。開発者の方々、お疲れさまです。今まで CVS を使っていたので、自分自身の環境としてとくに大きな変化はないものの、最新の SLIME がリリースされた意義は大きい。

SLIME について昨年夏に出たチュートリアルムービーはぜひ見ておきたい。リモートマシンで動作している CL プロセスにローカルの Emacs から SLIME を使ってアクセスする様子が見られる。色々なことを一気に見せてくれるので、SLIME のだいたいのイメージがつかめる。

Objective-C <= GC

下記の「Objective-C Mac OS Xプログラミング」をパラパラと斜め読みしていたら興味深い記述があった。もしかすると Mac OS X 10.5 (Leopard) にはガーベッジコレクションが載るかも知れないとのこと。Mac OS X 10.4 上で man cc の上 -fobjc-gc 参照。

Objective-C MacOS X プログラミング

Objective-C Mac OS Xプログラミング

Objective-C Mac OS Xプログラミング

生協に置いてあったので迷わず購入。著者の萩原さんは以前にも「Objective‐C―MacOS Xプログラミング入門」という本を書かれているが、こちらはかなり気に入っていて今でも大切に持っている(この本は評価が高いのだが残念ながら絶版となっていた)。書店に行けば Mac OS X のプログラミングについて解説した本は今なら選択肢がいくつかあるが、荻原さんのものは Objective-C についてきちんと書いてある本とあって貴重なものだった。今回の「Objective-C Mac OS Xプログラミング」は、「Objective‐C―MacOS Xプログラミング入門」の内容を継承しつつ、最新情報を盛り込んで書き直されたようだ。Objective-CCocoa Framework を Cocoa Framework たらしめている強力な言語なので、Mac でプログラムするならぜひ学んでおきたい。