2017-08-26 56 views
1

我有兩個包中都定義了一個類。第二個類繼承了第一個類,但有一個同名的插槽。其目的確實是爲了覆蓋插槽。禁止sbcl中的make-instance上的樣式警告

(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))) 

SBCL給出了一個有益的警示,當我做的bar

(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)來取消警告?

+3

如果您打算覆蓋插槽,則必須從其他軟件包導入名稱(或使用軟件包限定名稱)。現在,你有兩個插槽,'FOO :: S'和'BAR :: S'。 – jkiiski

+0

@jkiiski Doh!好,趕快,謝謝。 – user3414663

+1

這正是警告的內容;-) –

回答

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中會引用相同的符號。或者,您可以在包格式中編寫插槽名稱,但通常不推薦使用其他包的內部符號。

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繼承的確切位置取決於類metaobject的類;對於標準類,它在類的所有超類被定義之後的某個時候被調用,但不晚於類的第一個實例被分配(通過allocate-instance)。