此CLOS代码是否会导致Common Lisp中的运行时或编译时错误?

时间:2015-04-30 13:27:55

标签: common-lisp multiple-inheritance method-overriding clos

假设我写了下面这段代码(请原谅任何错误,我是Lisp新手,我不能在这台机器上运行CL)

(defclass o () ())
(defclass a (o) ())
(defclass b (o) ())
(defgeneric m (x))
(defmethod m ((x o))
   (print "O")
)
(defmethod m ((x a))
   (print "A")
   (call-next-method (make-instance 'a))
)
(defmethod m ((x b))
   (print "B")
   (call-next-method (make-instance 'b))
)

(setq aa (make-instance 'a))
(m aa) ;prints A, then O
(setq bb (make-instance 'b))
(m bb) ;prints B, then O

根据我的期望,它应该在没有任何投诉的情况下打印评论中所写的内容。

如果我添加以下代码会怎样?

(defclass c (a b) ())
(setq cc (make-instance 'c))
(m cc)

如果我理解标准方法组合,则cc的适用方法将排序为(m a)(m b)(m o)(m b)将不会由call-next-method成功调用。但实际会发生什么?当我定义类c并且说它使泛型函数m的方法链失效时,CL是否会抱怨?或者是否会出现运行时错误?

2 个答案:

答案 0 :(得分:1)

这应该在例外情况中发出错误according to the spec

  

当为call-next-method提供参数时,必须满足以下规则或者应该发出错误类型错误的信号:call-next-method的一组更改参数的有序方法必须是与泛型函数的原始参数的有序方法的有序集相同。可以优化错误检查,但它们不能改变call-next-method的语义。

正如您所说,拓扑类顺序将是:

  • c
  • a
  • b
  • o

文字图:

   o
 /   \
a     b
 \   /
   c

因此,适用方法的清单将是:

  • m (a)
  • m (b)
  • m (o)

因此,如果call-next-method没有发出错误信号,m (a)会将a传递给m (b),而b不是call-next-method

根据规范,这不应该发生,但我认为由于性能原因,实施可能会选择违反此规则。在每次调用call-next-method时计算适用的方法都很昂贵。

PS:事实上,根据实施情况,compute-applicable-methods-using-classes可以检查"顶级"新参数的匹配特化器与原始参数相同。要实现这一点,标准的计算区分函数必须更复杂,并且可能做一些非标准compute-applicable-methods{ error: { errors: [1] 0: { domain: “usageLimits” reason: “ipRefererBlocked” message: “There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed.” extendedHelp: “https://console.developers.google.com” }- – code: 403 message: “There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed.” }- } 可能不会做的副作用。

答案 1 :(得分:1)

它可能在编译时失败。它很可能在运行时失败。

m的对象的方法c顺序为:

(c a b o)

它会点击a,在a的新实例上调用下一个方法。 a方法m具有此方法顺序:

(a o)

由于这些方法顺序不同,call-next-method需要发出错误信号。撰写有关此内容的part of CLHS

  

为call-next-method提供参数时,必须遵循以下规则   应该满足或者应该发出类型错误的错误信号:有序的   更改参数集的适用方法集   call-next-method必须与有序的有序集相同   泛型函数的原始参数的方法。   可以优化错误检查,但它们不能   改变call-next-method的语义。

修复不是向call-next-method添加参数。完成编辑后,您可以在调用(m cc)时激活此打印:

"A" 
"B" 
"O" 

在CLISP中,它在运行时发出错误信号,而SBCL则没有,因此它实际上在SBCL中不合规格。