2017-08-26 12 views
1

それぞれにクラスが定義された2つのパッケージがあります。 2番目のクラスは最初のクラスを継承しますが、同じ名前のスロットを持ちます。実際にスロットを無効にする意図があります。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))) 

私は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) 

のインスタンスを作るときSBCLは、それが意図した動作であるので、私はこのようなことの警告を抑制することができる有用な警告を与える:

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

しかし、私は、 barクラスのユーザーは、警告を受け取らずにインスタンスを作成できるようになります。

前のコードブロックにコードを含むラッパー関数を書き込むことができましたが、すべてのスタイル警告を消さずに(make-instance 'bar)を呼び出す前に警告を抑制することは可能ですか?

+3

スロットを無効にする場合は、他のパッケージから名前をインポートするか、パッケージ修飾名を使用する必要があります。つまり、 'FOO :: S'と' BAR :: S'の2つのスロットがあります。 – jkiiski

+0

@jkiiski Doh!良いキャッチ、ありがとう。 – user3414663

+1

これはまさにその警告に関するものです;-) –

答えて

4

Common Lispのシンボルは通常、パッケージに属します。 Lispリーダーが新しいシンボルに遭遇すると、同じ名前のシンボルが他の場所からインポートされていない限り、それは現在のパッケージ(IN-PACKAGEによって設定)に入れられます。パッケージとシンボル名の間にコロン(または内部シンボルの場合は2つのコロン)を置くことによって、パッケージ名でシンボルを書くことができます。

我々は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実際に2つのスロット、FOO::SBAR::Sを持っています。スロット名は同じSYMBOL-NAMEですが、異なるSYMBOL-PACKAGEです。プログラマーが意図したことはまれであるため、SBCLは警告を出します。この問題を解決するにはFOO::Sをエクスポートして、パッケージBARの未修飾のSの書き込みが同じシンボルを参照するようにしてください。代わりに、パッケージ修飾フォームにスロット名を書くこともできますが、通常は他のパッケージの内部シンボルを使用することはお勧めしません。

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を参照してください。

最終的な継承が呼び出される正確なポイントは、クラスのメタオブジェクトのクラスによって異なります。標準クラスの場合は、クラスのすべてのスーパークラスが定義された後にいつでも呼び出されますが、クラスの最初のインスタンスが(allocate-instanceによって)割り当てられるときよりも遅くなります。

関連する問題