在sbcl中抑制make-instance上的样式警告

时间:2017-08-26 13:10:06

标签: common-lisp warnings sbcl clos suppress

我有两个包,每个包都定义了一个类。第二个类继承自第一个类,但有一个同名的插槽。意图确实是要覆盖这个插槽。

(defpackage :foo
  (:use :cl)
  (:export foo))

(in-package :foo)

(defclass foo () ((s)))

(defpackage :bar
  (:use :cl :foo)
  (:export bar))

(in-package :bar)

(defclass bar (foo) ((s)))
当我创建bar

的实例时,

sbcl会发出有用的警告

(make-instance 'bar)

STYLE-WARNING:
   slot names with the same SYMBOL-NAME but different SYMBOL-PACKAGE (possible
   package problem) for class #<STANDARD-CLASS BAR:BAR>:
       (FOO::S BAR::S)

由于这是预期的行为,我可以像这样抑制警告:

(handler-bind (#+SBCL (style-warning #'muffle-warning))
  (make-instance 'bar))

但是我希望bar类的用户能够在不收到警告的情况下创建实例。

我可以编写一个包含上一个代码块中代码的包装函数,但是可以在调用(make-instance 'bar)之前抑制警告,而不会消除所有样式警告吗?

2 个答案:

答案 0 :(得分:4)

Common Lisp中的符号通常属于一个包。当Lisp阅读器遇到新符号时,它将把它放在当前包中(由IN-PACKAGE设置),除非从其他地方导入了具有相同名称的符号。通过在包和符号名称之间放置一个冒号(或内部符号的两个冒号),可以使用包名写入符号。

如果我们在您的代码中添加包前缀,就像Lisp读者看到它们一样,错误就变得容易看到:

(cl:defpackage keyword:foo
  (keyword:use keyword:cl)
  (keyword:export cl-user::foo)) ;Makes FOO:FOO an external symbol, which will be 
                                 ; imported with the (:USE ... :FOO) below.
(cl:in-package keyword:foo)

(cl:defclass foo:foo () ((foo::s))) ;FOO::S is not exported, so it 
                                    ; is an internal symbol. It will 
                                    ; not be imported by the :USE-clause.

(cl:defpackage keyword:bar
  (keyword:use keyword:cl keyword:foo) ;Import all external symbols from CL and FOO.
  (keyword:export cl-user::bar))

(cl:in-package keyword:bar)

(cl:defclass bar:bar (foo:foo) ;FOO:FOO was imported from the other package.
  ((bar::s))) ;FOO::S (an internal symbol) wasn't imported, so a new
              ; symbol was interned in BAR.

班级BAR:BAR实际上有两个广告位FOO::SBAR::S。插槽名称具有相同的SYMBOL-NAME,但具有不同的SYMBOL-PACKAGE。这很少是程序员的意图,因此SBCL会对此发出警告。要解决此问题,您应导出FOO::S,以便在包S中编写不合格的BAR将引用相同的符号。或者,您可以使用包限定形式编写插槽名称,但通常不建议使用其他包的内部符号。

答案 1 :(得分:2)

这似乎警告在这里很有用,但是如果你发现自己处于一种必须扼杀它的情况,那么适当的地方就是在课程定稿时:

#+sbcl
(defmethod sb-mop:finalize-inheritance :around ((c (eql (find-class 'bar))))
   (handler-bind ((sb-int:simple-style-warning #'muffle-warning))
     (call-next-method)))

创建新实例时出错,但是当我测试代码时,在REPL中定义类时会发出错误信号。这是一个线索,即在类完成期间发出错误信号,必须在defclass之后(但不一定紧接在之后)和分配第一个实例之前完成。见Class finalization protocol

  

调用finalize-inheritance的确切位置取决于类metaobject的类;对于标准类,在定义了类的所有超类之后的某个时间调用它,但不迟于分配类的第一个实例时(通过allocate-instance)。