EIEIO(CLOS)如何覆盖父类上某个方法的after修饰方法


#1
ELISP> (defclass a () ())
a
ELISP> (defclass b (a) ())
b
ELISP> (cl-defmethod initialize-instance :after ((obj a) slots)
                     (message "A"))
initialize-instance
ELISP> (b)
#<b b-158d292010ac>

如代码所示,给a类的构造方法加了after修饰方法,导致b类初始化的时候也会打印“A”。请问是否有办法阻止b类执行此方法?


#2

你代码好像给错了,defmethod specialize on b。

如果你要给 a b 相同功能,又有功能只要 a 有而 b 没有,就给 a b 定义个共同的 parent。


#3

对,代码写错了,应该对a特化。

代码别人写的。。只能PR了,好麻烦。


#4

那你可以给 b 写个 :around,然后 (call-next-method)


#5

???可以举个例子么


#6
(defclass a () ())
a
(defclass b (a) ())
b

(cl-defmethod foo ((o a))
  (princ "a base\n")
  nil)
foo

(foo (make-instance 'b))
a base

(cl-defmethod foo :after ((o a))
  (princ "a after\n"))
foo

(foo (make-instance 'b))
a base
a after
nil

(cl-defmethod foo :around ((o b))
  (funcall (cl--generic-method-function
            (cl-find-method #'foo '() '(a)))
           o))
foo

(foo (make-instance 'b))
a base
nil

最后一个用的 cl--generic-method-function 是 emacs lisp specific 的 internal function,非常 dirty,你也可以直接 copy method on a 的 definition。

Common Lisp 是有 method combination 的,然而 eieio 这个重度鶸化版沒有这功能。

<#lisp> beach: ldbeth: If doing something like that is necessary, then there is something seriously wrong with the protocol design.

所以还是 PR 去吧。


#7

父类的构造方法是个空方法,正好我直接用around规避就完事了。

这群外国佬太闲了,又要倒时差,还是免了

代码洁癖发作了