オブジェクト関連で思ったこと
規約を翻訳して思ったことは、現状のnpt
ではかなり規約違反があるということです。
:allow-other-keys
なんて対応してないですもん。
地道に修正していこうと思います。
他、気になったことを忘れないように記載します。
qualifierはsymbol
だけじゃなくて何でも良かった?
自分が知らなかっただけですが、qualifierはnon-listとの記載がありました。
nil
以外のsymbol
だけが許容されるんだとばかり思っていたんですが、
何でも良かったんですね。
と思っていたんですが、確認してみるとどうもよくわからない。
ひとまずinteger
, character
, string
を試してみたんですが、
結果は下記の通り。
clisp
はinteger
,character
,string
を全部を受け付けるsbcl
はinteger
とcharacter
のみccl
はcharacter
,string
のみ
一例を下記に示します。
(define-method-combination test () ((code1 (10 20 "Hello")) (code2 (30 40 "aaabbb"))) `(progn ,@(mapcar (lambda (m) `(call-method ,m)) code1) ,@(mapcar (lambda (m) `(call-method ,m)) code2))) (defgeneric zzz (a) (:method-combination test)) (defmethod zzz 30 40 "aaabbb" (a) (format t "ccc ~A~%" a)) (defmethod zzz 30 40 "aaabbb" ((a integer)) (format t "bbb ~A~%" a)) (defmethod zzz 10 20 "Hello" (a) (format t "aaa ~A~%" a)) (zzz 999) →clispは正常に動作 →sbclはエラー、stringの"Hello", "aaabbb"がダメ →cclはエラー、integerの10, 20, 30, 40がダメ
正常パターンの動作結果は下記の通り。
aaa 999 bbb 999 ccc 999
なんなんだこれは。
まあqualifierなんてもんは、
symbol
だけを使うのが無難なんじゃないでしょうか。
1つか複数の返却値ってのはおかしい
0個の返却値も含まれるはず。
この文は「7.6.6.2 Standard Method Combination」あたりに出てくるものであり、
methodの返却値がgeneric-functionでどう扱われるかを説明したものです。
自分で訳しておいてケチ付けるのもアレですが、 たぶん翻訳がおかしいんだと思います。 元の文は「value or values」となっており、 それを「1つか複数の返却値」みたいに訳しています。 でも、たぶん複数の返却値もちゃんと考慮するんですよっていう 気遣いなんじゃないかと思うんですよ。
【間違い】defstruct
がmethod-defining formsに入っているのはおかしいのでは?
【追記】すみません、間違いです。投稿してから気が付きました。
methodの定義は、reader
/writer
ではなく、print-object
を対象にしています。
よってこの章の言ってることは間違いです。
これは規約の間違いなんじゃないかと思います。
「7.6.1 Introduction to Generic Functions」の「Figure 7-1.」では、
メソッドを定義するオペレーターの中にdefstruct
を入れています。
でもdefstruct
はreader
/writer
にあたる関数の生成機能はありますが、
ぜんぶ通常の関数を対象にしているため、generic-functionの生成機能はないはず。
だからこそ、defstruct
が生成する関数は、generic-function特有の
effective methodを特定する動作がない分だけちょっと早いはずなんです。
早いといってもクソみたいな差だと思いますが。
でも自分はまだdefstruct
を作成したことが無いので
勘違いしているかもしれません。
共有スロットはクラス宣言時にはまだ確保されていないかも?
ANSI Common Lisp範囲外の話だと思います。
規約では7.5.1章に「Defining a shared slot immediately creates a slot.」
みたいに書かれています。
共有スロットが宣言されたとき、即座にスロットが作成されるという意味です。
でもdefclass
なんかで:allocation
が:class
のスロットを宣言した瞬間では、
まだそのスロットは値の確保などが済んでいないかもしれません。
sbcl
では、class-prototype
経由で共有スロットにアクセスすると、
まだfinalizeが完了していないということでエラーになってしまいます。
以前説明したforward-referenced-class
関係の話ですね。
でもmake-instance
を経由してもらえば全然大丈夫なので、
これを規約違反とみなすのは無理があるとは思います。
標準のmethod-combinationは例文を見た方がわかりやすい
標準のmethod-combinationと言えば、standard
か、
or
といった短いフォームになりますが、
使い方を覚えようとしていた時代は、何の解説書を見ても
いまいち良くわからなかったことを覚えています。
規約には難しそうなことがごちゃごちゃ書かれていますが、
処理系を実装するんじゃない限り
define-method-combination
の使い方をちょっとだけ覚えてから
マクロdefine-method-combination
の規約に記載されている
例文を見た方がわかりやすいのではないでしょうか。
下記に例文を抜き出します。
- Macro DEFINE-METHOD-COMBINATION
;The default method-combination technique (define-method-combination standard () ((around (:around)) (before (:before)) (primary () :required t) (after (:after))) (flet ((call-methods (methods) (mapcar #'(lambda (method) `(call-method ,method)) methods))) (let ((form (if (or before after (rest primary)) `(multiple-value-prog1 (progn ,@(call-methods before) (call-method ,(first primary) ,(rest primary))) ,@(call-methods (reverse after))) `(call-method ,(first primary))))) (if around `(call-method ,(first around) (,@(rest around) (make-method ,form))) form))))
短いフォームは次の通り。
;The same thing, using the :order and :required keyword options (define-method-combination or (&optional (order ':most-specific-first)) ((around (:around)) (primary (or) :order order :required t)) (let ((form (if (rest primary) `(or ,@(mapcar #'(lambda (method) `(call-method ,method)) primary)) `(call-method ,(first primary))))) (if around `(call-method ,(first around) (,@(rest around) (make-method ,form))) form)))
わからないならごめんなさい。