Common lispの場合:スコープ内の既存の関数を再定義しますか?OPは似たようなものを求めました。しかし、関数ではなく、メソッドスペシャライザーを作成したいと思います。基本的に、メソッドが次のように定義されていると仮定します。
defmethod my-meth ((objA classA) (objB classB)) (...)
私がやりたいのは(擬似コード)です:
(labels ((my-meth ((objA classA) (objB (eql some-object)))))
do stuff calling my-meth with the object...)
実際の用途は、特定のオブジェクトのスロット書き込みのオンデマンドインターセプトを本質的に作成するsetf slot-value-using-class
ことに特化した一時的な環境を作成したいということです。eql
(目的は、古いスロット値と新しいスロット値をどこかに記録してから、次のメソッドを呼び出すことです。)すでにインスタンス化された標準オブジェクトをインターセプトしたい場合があるため、メタクラスを作成したくありません。
もちろん試してみましたが、うまくいきませんでしたが(どうやってDEFMETHOD
?LABELS
)、経験豊富な人にそのような方法で実行できないことを確認したり、適切な方法を提案したりしたいと思いました。
コメント?
編集:
DanielとTerjeは、可能性に向けて私の知識を広げるための優れたリンクを提供しますが、そこに行く前に、よりバニラなアプローチを探すためにもう少しプッシュしたいと思います。私は、環境に入るときにadd-methodを実行することを検討してきました。これは、eqlに特化し、終了時にremove-methodを実行します。私はまだ終わっていません。誰かがそれらで遊んだことがあるなら、コメントはいいでしょう。スレッドを最新の状態に保ちます。
編集2:私はadd-methodシナリオでそれを行うのに近いですが、問題があります。これが私が試したことです:
(defun inject-slot-write-interceptor (object fun)
(let* ((gf (fdefinition '(setf sb-mop:slot-value-using-class)))
(mc (sb-mop:generic-function-method-class gf))
(mc-instance (make-instance (class-name mc)
:qualifiers '(:after)
:specializers (list (find-class 't)
(find-class 'SB-PCL::STD-CLASS)
(sb-mop::intern-eql-specializer object)
(find-class 'SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION))
:lambda-list '(new-value class object slot)
:function (compile nil (lambda (new-value class object slot) (funcall fun new-value class object slot))))))
(add-method gf mc-instance)
(defun remove-slot-write-interceptor ()
(remove-method gf mc-instance))
))
(defun my-test (object slot-name data)
(let ((test-data "No results yet")
(gf (fdefinition '(setf sb-mop::slot-value-using-class))))
(labels ((show-applicable-methods () (format t "~%Applicable methods: ~a" (length (sb-mop:compute-applicable-methods gf (list data (class-of object) object (slot-def-from-name (class-of object) slot-name)))))))
(format t "~%Starting test: ~a" test-data)
(show-applicable-methods)
(format t "~%Injecting interceptor.")
(inject-slot-write-interceptor object (compile nil (lambda (a b c d) (setf test-data "SUCCESS !!!!!!!"))))
(show-applicable-methods)
(format t "~%About to write slot.")
(setf (slot-value object slot-name) data)
(format t "~%Wrote slot: ~a" test-data)
(remove-slot-write-interceptor)
(format t "~%Removed interceptor.")
(show-applicable-methods)
)))
オブジェクトスロットとデータを引数として(my-test)を呼び出すと、次のようになります。
Starting test: No results yet
Applicable methods: 1
Injecting interceptor.
Applicable methods: 2
About to write slot.
Wrote slot: No results yet <----- Expecting SUCCESS here....
Removed interceptor.
Applicable methods: 1
だから私はここで立ち往生しています。適用可能なメソッドにeql-specialized:afterメソッドが含まれるようになったため、特殊化は機能しますが、残念ながら呼び出されないようです。誰かが助けてくれるので、私はそれを終えて、それを甘い小さなユーティリティマクロにリファクタリングすることができますか?