5

サードパーティのライブラリがファイナライズされたかのようにクラスに作用する必要があるという問題に遭遇しました。少し読んだ後、このメカニズムの背後にある動機を理解しましたが、それがどのように機能するかはよくわかりません.

例:

(make-instance 'expression :op '+ :left 'nan :right 'nan)
(defmethod normalize-expression ((this expression))
  (optima:match this
    ((optima::or (expression :left 'nan) (expression :right 'nan)) 'nan)
    ((expression :op op :left x :right y) (funcall op x y))))

最初の行を追加しない限り、関数はコンパイルされず、次のエラーが発生します。

; caught ERROR:
;   (during macroexpansion of (SB-PCL::%DEFMETHOD-EXPANDER NORMALIZE-EXPRESSION ...))
;   SB-MOP:CLASS-SLOTS called on #<STANDARD-CLASS EXPRESSION>, which is not yet finalized.
;   See also:
;     AMOP, Generic Function SB-MOP:CLASS-SLOTS

optimaはパターン マッチング ライブラリであり、指定されたパターンに対して(expression :op op ...)クラスのインスタンスをマッチングしますexpression。詳細はわかりませんが、このクラスに定義されているアクセサを知る必要があるようで、その情報は確定するまで利用できないようです。では、ファイナライズの問題を回避する方法はありますか?

クラスは延長されません (少なくともこのプロジェクトでは延長されず、計画されていません)。ダミーのインスタンスを作成してもそれほど害はありません...それはただの醜い解決策なので、より良い解決策を見つけたいと思っていました。また、おそらく、ファイナライズに関する詳細情報も得られるでしょう。これも良いことです:)

4

1 に答える 1

9

クラスのファイナライズを確実にするのを忘れることは、MOP を使用するときによくある間違いのようです。

Lisp では、クラスは 2 つの「フェーズ」で定義されます。

  • 直接クラス定義
  • 実効クラス定義

クラスの直接定義はdefclassフォームと同形です。これには、クラス名、スーパークラスの名前、直接スロットのリスト (つまり、この特定のクラスで定義されているが、そのスーパークラスで定義されているスロット) があります。

効果的なクラス定義には、コンパイラ/インタプリタに必要なすべての情報が含まれています。これには、すべてのクラス スロット (スーパークラスで定義されたものを含む)、クラス インスタンス レイアウト、アクセサ メソッドへの参照などのリストが含まれます。

直接のクラス定義を有効なクラス定義に変換するプロセスは、クラスのファイナライズと呼ばれます。CLOS はクラスの再定義をサポートしているため、ファイナライズはクラスに対して複数回呼び出される場合があります。ファイナライズが遅れる理由の 1 つは、スーパークラスが定義される前にクラスが定義される可能性があるためです。

あなたの特定の問題に関して:optima:matchスロットをリストする前に、クラスがファイナライズされていることを確認する必要があるようです。class-finalized-pこれは、 (クラスのファイナライズが必要かどうかを確認するため) とfinalize-inheritance実際にファイナライズを実行するための 2 つの関数で実行できます。または、ユーティリティ関数を使用できますcloser-mop:ensure-finalized。(closer-mop は、CLOS MOP をポータブルに使用するためのライブラリです)。

例えば、:

(c2mop:ensure-finalized (find-class 'expression))
于 2013-07-30T04:13:26.083 に答える