Next: 14.4 メソッドの探索
Up: 14 オブジェクト指向機能の実現
Previous: 14.2 メソッドの実現
インスタンスの生成というのは,クロージャの生成になる.
関数instanceは以下のように,クラス名と初期メッセージ(args)を
与えると(self x &rest args)という引数を受けとるクロージャを
返す.
クロージャに保存される局所変数は,
(class-local-variables (get-class class-name))
である.つまり,クラスに宣言されているインスタンス変数のリストが
クロージャ定義のlet文の局所変数宣言のところに渡される.
(defun instance (class-name &rest args)
(let
((ins (create-instance
class-name
(class-local-variables
(get-class class-name)))))
(if args (apply ins (cons ins args))
ins)))
(defun create-instance (class-name vars&values)
(eval `(internal-create-instance
,class-name ,vars&values)))
(defmacro internal-create-instance (class-name vars-values)
`(let ,vars-values
#'(lambda (self x &rest args)
(let ((method (find-method x ',class-name)))
(if method
#+:allegro
(apply (excl::make-lexical-closure method)
(cons self args))
#-:allegro
(apply method (cons self args))
(error "~a undefined method for class ~a"
x ',class-name))))))
クロージャは,送られてくるメソッドがクラス(class-name)に
登録されているかどうか探しだし(find-method),そのメソッドが
あればそれを実行する,というように作る.
ここでは,そのメソッドがlambda式になっている.
上の定義で用いられている,#+:allegroは,*features*という
大域変数に:allegroというシンボルが含まれているかどうかを調べて,
含まれていればその次のS-式を読み込むという意味である.
#-:allegroは含まれていなければ読み込むという意味である.
Allegro Common Lisp(ACL)では,標準環境で,
<cl> *features*
(:UNIX :SUN4 :SUN :ALLEGRO :ALLEGRO-V3.0
:COMMON-LISP :EXCL :FRANZ-INC :GSGC)
というように*features*が初期設定されている.
そのため,ACLでは,最初の方が定義として
使われ,Xlispでは後者が使われる.
ACLの場合の定義にある,
excl::make-lexical-closure
は,ACL特有の組み込み関数である.
これは引数のフォームをlexical-closureに変換する
ものです.つまり,そのクロージャが作られた時の字ずらの
環境が保存されたクロージャを作る.
上のプログラムでは,vars-valuesの中に現れる局所変数が
その環境として保存される.
こうすることで,たとえば,x-positionというメソッドにおいて,
インスタンス固有の変数であるx-positionの値を知りたい時に,
ただx-positionを返すように書いておくだけですむことになる.
この場合,vars-valuesの中にx-positionが現れ,変数methodが
(lambda () x-position)という式になり,
このx-positionがvars-valuesに現れたx-positionであるとみなされる
ことになる.
xlispの場合には,applyの引数のフォームに現れる変数がレキシカルバインディ
ングされているものとして取り扱うためこのような変換を行なわなくてもよい
ということになっている.
generated through LaTeX2HTML. M.Inaba 平成18年5月7日