forward-referenced-classとは何か
そんなクラス知らねえと言われても仕方がないほどマイナーなものです。
こいつは、だいたいはmop関連のパッケージに隠れています。
ANSI Common Lispには制定されていませんが、
CLOSを構築する際に必要となるので標準みたいなものでしょう。
まだあんまり読めてないんですが、 The Art of the Metaobject Protocolっていう専門書に載ってないんですよね。 検索しても日本語の解説は出てこない。 Common Lisp自体が古いから仕方がないといえば仕方がない。 じゃあ自分が書くか。
処理系依存ですが、次のようにすると確認できます。
* (find-class 'sb-mop::forward-referenced-class) #<STANDARD-CLASS SB-MOP:FORWARD-REFERENCED-CLASS>
ccl
? (find-class 'ccl::forward-referenced-class) #<STANDARD-CLASS FORWARD-REFERENCED-CLASS>
> (find-class 'clos::forward-referenced-class) #<STANDARD-CLASS FORWARD-REFERENCED-CLASS>
これは一体何なのかというと、defclass
で先行して存在しないsuperclass
を指定したときに
仮決めとして指定されます。
クラスを先行して設定した例をもとに説明します。
(defclass aaa (bbb) ()) ;; ★まだbbbは存在しない (defclass bbb () ((hello :initform "zzz"))) (slot-value (make-instance 'aaa) 'hello)) →"zzz"
では内部でどうなっているのか見てみます。
モップを使いますので、sbclならsb-mop
をuse-package
してください。
* (use-package 'sb-mop)
なんか清掃用具みたいですね。
まずは綺麗な状態から、再びクラスaaa
を作成します。
* (defclass aaa (bbb) ()) ;; ★まだbbbは存在しない #<STANDARD-CLASS COMMON-LISP-USER::AAA>
この状態でsuperclassの内容を確認します。
* (class-direct-superclasses (find-class 'aaa)) (#<FORWARD-REFERENCED-CLASS COMMON-LISP-USER::BBB>)
存在しないはずのクラスbbb
は、forward-referenced-class
と出てきています。
この表記から、forward-referenced-class
はmetaclass
だということがわかります。
ではクラスbbb
を作成します。
* (defclass bbb () ((hello :initform "zzz"))) #<STANDARD-CLASS COMMON-LISP-USER::BBB>
superclassはどうなっているでしょうか。
ここは処理系によって分かれました。
sbclの例を示します。
* (class-direct-superclasses (find-class 'aaa)) (#<STANDARD-CLASS COMMON-LISP-USER::BBB>)
class-of
がstandard-class
に変わっています。
この時点で確定するってすごいですね。
どうやっているんだろう。
bbb
をfind-class
にreferenced-class
として登録していたのか、
あるいはclass-direct-superclasses
の実行契機で見直したのか。
cclも確定していました。
? (class-direct-superclasses (find-class 'aaa)) (#<STANDARD-CLASS BBB>)
clispはまだ保留中です。
> (class-direct-superclasses (find-class 'aaa)) (#<FORWARD-REFERENCED-CLASS BBB>)
いずれにせよ、finalizeした時点で確定します。
classをfinalizeさせます。
> (make-instance 'aaa) #<AAA #x000801C57458>
あらためてsuperclassを確認します。
> (class-direct-superclasses (find-class 'aaa)) (#<STANDARD-CLASS BBB>)
なるほど。
ということは、forward-referenced-class
を持っている場合は
当然class-precedence-list
は作成できない?
[1]> (defclass aaa (bbb) ()) ;; ★まだbbbは存在しない #<STANDARD-CLASS AAA :INCOMPLETE> [2]> (class-precedence-list (find-class 'aaa)) *** - The class #<STANDARD-CLASS AAA :INCOMPLETE> has not yet been finalized. The following restarts are available: ABORT :R1 Abort main loop Break 1 [3]>
finalizeしないとダメだそうです。
finalizeがされたかどうかの確認は次のようになります。
> (class-finalized-p (find-class 'aaa)) NIL
ちなみにclass-precedence-list
の実行結果は、
でした。
まあどれでもいいんじゃないでしょうか。
不完全なクラスはdefclass
やensure-class
では作成を途中で放棄し、
最大限まで仕事を遅らせて、make-instance
なんかでfinalizeする必要が生じたとき、
ようやく重い腰をあげることがわかりました。
めんどくさい!