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规避就完事了。

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

代码洁癖发作了


#8

今天看了下EIEIO的多态函数实现cl-generic是支持方法组合的,只要实现cl-generic-combine-methods这个方法就可以了。


#9

那就是你要自己实現一个向后兼容 :after :before :around :extra 又能自定义的 method combination 方法,因为这个 method 沒法用参数 dispatch 只能全局覆蓋。估计本來他要在这里做 define-method-combination 界面的然而后來咕咕了


#10

可以dispatch,他自己也是用cl-defmethod定义的,不过bootstrap的时候有一点hack

(unless (ignore-errors (cl-generic-generalizers t))
  ;; Temporary definition to let the next defmethod succeed.
  (fset 'cl-generic-generalizers
        (lambda (specializer)
          (if (eq t specializer) (list cl--generic-t-generalizer))))
  (fset 'cl-generic-combine-methods #'cl--generic-standard-method-combination))

但是要拆开cl--generic-standard-method-combination就有点麻烦了。换我就分开提取和组合两个部分,而不是像他这样全部挤在一起


#11

所以 CLOS 给了 define-method-combination,用户只要写组合方法

(cl-defmethod cl-generic-combine-methods (generic methods)

这里面 generic, methods 哪个参数可以 dispatch/specialize?


#12

可以用aroud然后call-next-method


#13

那不就是全局覆蓋,对于題问里的就只要 override 某个 class 的要求过于 over kill 了


#14

完全不懂cl-lib和EIEIO old McDonald had a farm…,你们都怎么学,直接学common lisp吗。。


#15

对对对。

其实也不一定要用EIEIO的class,可以用cl-lib里面的struct和generic实现类似Rust那种只有trait的语言的功能,更别说struct直接就支持单继承


#16

有没有比较pratical的讲解方法组合的文章?


#17

Object-Oriented Programming: The CLOS Perspective 的第一章