実践Common Lisp p183-212

オブジェクト指向再入門らしいですけど、入門した覚えがない。でもとりあえず再入門してみます。
長くなったのでたたみます。

  • CLOSについては後でもうちょっと調べてみよう。
  • ポリモーフィズムってよく聞くけどそういうことだったんだー。

  • call-next-method??って思ったけど上のクラスのメソッドをもう一度呼ぶのか。なんで最後にcall-next-methodが必要なのかと思ったんだけど、whenの部分だとdecfされてないですね。単にdecfしたあとマイナスにならないようにincfしてるだけでした。そうすると引き落とす処理を書かなきゃいけないけど、その処理は既に上のクラスbank-accountで定義したからわざわざその処理を書かなくても渡してしまえば同じ事をやってくれるってことですね。なるほど。

    (defmethod withdraw ((acount checking-account) amount)
      (let ((overdraft (- amount (balance account))))
        (when (plusp overdraft)
          (withdraw (overdraft-account account) overdraft)
          (incf (balance account) overdraft)))
      (call-next-method))
    

  • メソッド結合面倒くさい。とりあえず下の方のクラスから呼ばれるのが分かった。あとは:around,:before,基本,:afterで呼ばれることも分かった。:aroundはcall-next-methodを呼ぶ必要がある。だから基本的には:before->基本->:afterというのがメソッド結合の骨組みで、aroundはその周囲を整えるような印象なんだろうか。:beforeは前処理、基本は具体的な処理、:afterは後処理みたいな。うーん。ややこしいな。
  • あぁ、スロットってそういうことか。他の本でこの単語が出てきてなんとなくで読んでました。

  • なるほど。INITIALIZE-INSTANCEがSTANDARD-OBJECTに特定化された基本メソッドだから、:afterを使えばその後にしたい処理を書けるのか。便利だ。
  • setf関数。setfはマクロだろと思ったらsetf関数があるんですね。defun,defmethodなどの名前の部分がSchemeみたいになってます。普通のdefunのsyntaxじゃないですね。REPLで(defun (x y) () 3)とするとエラー出てきますし。それじゃあdefunのname部分は評価されるのかなと思ったけど、

    CL-USER> (defun foo () 'a)
    FOO
    CL-USER> (defun (foo) () 3)
    ; Evaluation aborted.
    

    そういうわけでもなさそうだし。そうするとdefunやdefmethodのnameの部分が(setf ...)の形の時は特殊なsyntaxとして受け入れられるんですかね。ググっても全然情報がないんで適当なこといってるかもしれませんが。とりあえず使うだけなら、

    (defun (setf f) (value rest1 rest2 ...)
      <body>)
    

    とすることでsetfマクロを拡張することができて、

    (setf (f arg1 arg2 ...) real-value)
    

    という呼び出しの際には、value=real-value, rest1=arg1, rest2=arg2, ...というbindのもとでsetf関数が呼び出され、が評価される。こんな感じに解釈しましたが、なんでそうなるのか調べても全然書いてないのでとてももやもやします。

  • だからp204で

    (setf (customer-name *account*) "Sally Sue")
    (customer-name *account*)
    

    とありますが、この二つで使われているcustomer-nameは同一ではなくて、上の方はsetf関数の名前の二つ目のシンボルで、下の方は値を参照するために作った関数。のはず。たぶん。でもコードだけ見るとcustomer-nameはまるで*account*のメンバの場所を返しているように見えるのでコードの意味はわかりやすい。たぶんそういう効果があるってことなんでしょうか。うーん。

  • スロット指定子の:initformオプションは最も下位のものを使う。:initargは矛盾しないから大丈夫。:readerと:writerと:accessorは継承されない。:allocationは:initformと同じで現在のクラス以上で一番下のもの。
  • 多重継承ではdefclassのスーパークラスのリストを渡す引数で、そのリストの順番に特定度が高いとされるらしい。


全体的な感想としては、すごくややこしい。でもものにできたらプログラムの抽象化が上手くなったりするのかなぁ。よく分からないところが多かったので感想の量が多くなってしまった。