Common lisp 此CLOS代码是否会导致公共Lisp中的运行时或编译时错误?
假设我编写了以下代码(请原谅任何错误,我是Lisp新手,无法在此机器上运行CL) 按照我的期望,它应该打印评论中写的内容,没有任何抱怨 如果我添加以下代码会发生什么Common lisp 此CLOS代码是否会导致公共Lisp中的运行时或编译时错误?,common-lisp,multiple-inheritance,overriding,clos,Common Lisp,Multiple Inheritance,Overriding,Clos,假设我编写了以下代码(请原谅任何错误,我是Lisp新手,无法在此机器上运行CL) 按照我的期望,它应该打印评论中写的内容,没有任何抱怨 如果我添加以下代码会发生什么 (defclass c (a b) ()) (setq cc (make-instance 'c)) (m cc) 如果我理解标准方法组合,则cc的适用方法将被分类为(MA),(MB),(MO),(MB)将不会被调用下一个方法成功调用。但实际会发生什么呢?当我定义类c并说它使泛型函数m的方法链无效时,CL会抱怨吗?或者是否会出现运
(defclass c (a b) ())
(setq cc (make-instance 'c))
(m cc)
如果我理解标准方法组合,则
cc
的适用方法将被分类为(MA)
,(MB)
,(MO)
,(MB)
将不会被调用下一个方法成功调用。但实际会发生什么呢?当我定义类c
并说它使泛型函数m
的方法链无效时,CL会抱怨吗?或者是否会出现运行时错误?在异常情况下,这应该是一个错误信号:
当提供参数以调用下一个方法时,必须满足以下规则或发出错误类型的信号:调用下一个方法的已更改参数集的适用方法的有序集必须与泛型函数的原始参数的适用方法的有序集相同。错误检查的优化是可能的,但它们不能改变callnext方法的语义
正如您所说,拓扑类顺序将是:
c
a
b
o
文本图:
o
/ \
a b
\ /
c
因此,适用方法清单如下:
m(a)
m(b)
m(o)
因此,如果调用下一个方法
没有发出错误信号,m(a)
将a
传递给m(b)
,这不是ab
根据规范,这不应该发生,但我相信一个实现可能会因为性能原因而选择违反这个规则。每次调用callnext method
时,计算适用方法的成本很高
PS:事实上,根据实现的不同,callnext方法
可以检查新参数的“顶级”匹配专门化器列表是否与原始参数相同。为了实现这一点,标准的计算判别函数必须更加复杂,并且可能会做一些非标准的使用类计算适用的方法和计算适用的方法可能无法做的辅助工作。它可能会在编译时失败。它很可能在运行时失败
类c
对象的方法m
顺序为:
(c a b o)
它将点击a
,其中将对a
的新实例调用下一个方法a
对方法m
具有此方法顺序:
(a o)
由于它们具有不同的方法顺序,调用下一个方法
需要发出错误信号。这篇文章的作者是:
当提供参数来调用下一个方法时,必须遵循以下规则
或应发出错误类型错误的信号:订购
已更改的参数集的适用方法集
call next方法必须与适用的
泛型函数的原始参数的方法。
错误检查的优化是可能的,但它们不能
更改callnext方法的语义
解决方法是不向调用下一个方法添加参数。编辑完成后,您可以在调用(m cc)
时取消打印:
在CLISP中,它在运行时发出错误信号,而SBCL不发出错误信号,因此它实际上在SBCL中不符合规范 我猜您希望第一个defmethod
将其参数专门化为o
,对吗?您应该使用make instance
,而不是allocate instance
,它需要一个符号,所以您需要在给出时逐字引用它。我只使用规范编写代码,所以可能会犯一些错误。谢谢。它不应该在编译时失败。它应该在运行时失败,但正如您所看到的,当指定不同的参数时,某些实现不遵循调用下一个方法
规则,因此在实践中,它可能不会在运行时失败。@PauloMadeira它会失败的可能性不大,但规范中没有任何反对它的内容。我就是这样读的“错误检查的优化是可能的,但它们不能改变调用下一个方法的语义。”。但这是关于调用下一个方法的行为,而不是编译对它的调用的行为。出于某种原因,调用(m aa)
会导致SBCL中的“AOO”,知道为什么m(o)
被调用了两次?它没有。它在m(A)
中打印“A”
,然后在m(O)
中打印“O”
,然后REPL打印结果,这是print
的参数,这是字符串“O”
。因此,这两个“O”“
s您看到的是REPL的副作用。要证明这一点,请尝试调用(progn(m aa)(values))
,或在m(o)
中添加(values)
作为最后一个表单。
(a o)
"A"
"B"
"O"