next up previous
Next: 9.4 メソッドの探索 Up: 9 オブジェクト指向言語の実現 Previous: 9.2 メソッドの実現

9.3 Instance生成

インスタンスの生成というのは,クロージャの生成になります. 関数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は含まれていなければ読み込むという意味です. アレグロコモンリスプaclでは,標準環境で,

<cl> *features*
(:UNIX :SUN4 :SUN :ALLEGRO :ALLEGRO-V3.0
   :COMMON-LISP :EXCL :FRANZ-INC :GSGC)
というように*features*が初期設定されています. そのため,アレグロコモンリスプでは,最初の方が定義として 使われ,Xlispでは後者が使われます. アレグロコモンリスプの場合の定義にある, excl::make-lexical-closure は,アレグロコモンリスプ特有の組み込み関数です. これは引数のフォームを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月6日