2

私はsmalltalkにあまり詳しくありませんが、自分のクラスを初期化するときに、別のクラス「new」をオーバーライドしようとしています。それはClass>>bindingOf :と関係がありますか?

編集:

私が達成しようとしているのは、ObjectAがを呼び出す場合new、ObjectBが要求を処理することです。
ObjectBはObjectAとは関係ありません。
これは、ObjectBの実装を変更するだけで実行できますか?

編集:ObjectBこのストーリーの私のObjectTracerものはであり、私がやりたいことは、のラッパークラスのように動作することですObjectAObjectAクラスのメソッドディクショナリを使用するためにの実装を変更newしますか?それはどのように行われますか?

編集:これが私が可能にしたいことです:

| obj |
obj := ObjectA new.
obj aMethod.

実際に起こっていることは、newに送信されたときに、(ラッパー)ObjectAによって提供される実装に置き換えられ、ObjectBaka.niceやHernanのように、回答で言及されているように、を対象としたメッセージObjectBを処理することです。基本的に、必要なのはのを置き換える ことだけである可能性はありますか?#doesNotUnderstandObjectA
ObjectBObjectA#new

4

5 に答える 5

5

ほとんどのトレーサー、プロファイラー、およびサンプラーは、システムの実行を監視します。システムを実際に変更するトレーサーを開発する場合は、付随的な影響を回避するために、そのダイナミクスを十分に理解する必要があります。

これは、トレーサーの基本的な式です。

  • anObjectAをトレーサー(anObjectB)でラップします
  • 「object」インスタンス変数を使用してTracerクラスを作成します(ほとんどのTracersサブクラスはnilなどから)
  • トレーサーのクラス側に#initializeを実装して、スーパークラスポインターを削除します(superclass:= nil)
  • トレーサーのオブジェクトにanObjectAを格納するために、トレーサーのクラス側に#on:anObjectAを実装しますiv

次のテンプレートのように、Tracerのインスタンス側に#doesNotUnderstand:aMessageを実装します。

doesNotUnderstand: aMessage
"trace the selector then pass the message on"

| result |
aMessage arguments size = 0
  ifTrue:
    [result := object perform: aMessage selector]
  ifFalse:
    [result := object perform: aMessage selector withArguments: aMessage arguments].
^result

あなたの場合、#perform:sendの前に、ObjectAメソッドディクショナリにアクセスして、「aMessage」CompiledMethodを別のディクショナリに置き換えることができます。クラスのメソッドディクショナリにアクセスするには、一部のSmalltalkで#methodDictionaryまたは#>>を送信しました。

リフレクションの方法を知っている場合は、新しいコンパイル済みメソッドを配置するか、辞書全体を置き換えることもできます。

| methodDictionary |
methodDictionary := MethodDictionary new.
methodDictionary at: #basicNew put: (Object compilerClass new
                                compile: 'basicNew ^Point basicNew'
                                in: Object
                                notifying: nil
                                ifFail: []) generate.

評価するためにMethodDictionaryに常駐するメソッドは必要ないことに注意してください。#valueWithReceiver:argumentsの送信者を参照してください:

最後に、新しいオブジェクトに送信します

anObjectA := MyTracer on: ObjectA new.
anObjectA example1.

はい、それをObjectAの新しいメソッドにも入れることができます。Smalltalkのリフレクションに関するいくつかの章をよく読んでください。Smalltalkは計算によるリフレクションを行うための最良のプラットフォームであるため、Webには多くのコンテンツがあります。

于 2012-12-09T20:21:53.857 に答える
3

いいえ、#bindingOf:はメソッドのコンパイルに関連しています。

グローバル変数、クラス変数、プール変数など、いくつかのメソッドを介してアクセスできる変数は、メソッドリテラルに同じバインディングを格納することで共有されます。バインディングは、キーが変数名で値が変数値である一種の関連付けです。

コードで変数を使用する場合、メソッドは内部のバインディングに#valueを送信し、変数に値を格納すると、#valueを送信します。

ただし、Smalltalkのフレーバーによっては、これらの操作がバイトコードで最適化され、バインディングの2番目のインスタンス変数(値)への直接アクセスに置き換えられる場合があることに注意してください。

したがって、コンパイラは、共有変数にアクセスするために、bindingOf:aSymbolを取得する必要があります。ここで、aSymbolは変数の名前です。変数アクセスのスコープはクラスに依存するため、メソッドがコンパイルされるクラスはその情報について照会されます(クラスとそのサブクラスのみがクラス変数にアクセスできます...)。

YourClassでのインスタンス作成をオーバーライドする場合は、クラス側で#newをオーバーライドするだけです(YourClassクラス>> #newと言います)。Squeak / Pharo方言を使用する場合、ほとんどの場合、#newは#initializeを呼び出すため、インスタンス側(YourClass >>#initialize)で#initializeをオーバーライドすることで特定のインスタンス化を実現できます。

編集

ObjectTracerを使用してObjectAへの#newの送信をキャッチしたい場合は、次のことができます。

| theTrueObjectA |
theTrueObjectA := ObjectA.
[Smalltalk globals at: #ObjectA put: (ObjectTracer on: ObjectA).
"insert the code you want to test here"
ObjectA new]
    ensure: [Smalltalk globals at: #ObjectA put: theTrueObjectA].

EDIT2の最後の文は次のように置き換えることができますensure: [ObjectA xxxUnTrace]

ただし、最新のsqueakデバッガーは煩わしく、それ自体がObjectTracerに多くのメッセージを送信して、他のデバッガーがポップする原因になります...最初に[設定]ウィンドウを開き、logDebuggerStackToFileを無効にする必要があります。

関連するメカニズムは、メッセージ#doesNotUnderstand:がメッセージを理解しないときにオブジェクトによって送信されることであることに注意してください。ObjectTracerは#doesNotUnderstand:をオーバーライドして、デバッガーをポップアップします。

ProtoObjectをサブクラス化して、独自の#doesNotUnderstand:処理をインストールできます(トランスクリプトやファイルに何かを書き込むようなものです)。

また、ObjectTracer #inheritsFrom:ProtoObjectおよびProtoObject自体#respondsTo:ProtoObject >>#doesNotUnderstandによってキャッチされない多くのメッセージに注意してください。

最後の注意:理解できるメッセージを示すために上記の#を使用しました。

編集3:考えられる解決策は、2つのインスタンス変数tracedObjectとmessageMappingを使用して新しい種類のObjectTracerを定義し、このインスタンスを作成することです。

MessageInterceptor class>>on: anObject interceptMessages: aDictionary
    "Create an interceptor intercepting some messages sent to anObject.
    aDictionary keys define message selectors that should be intercepted.
    aDictionary values define block of code that should be evaluated in place.
    These blocks always take one argument for passing the traced Object,
    plus one argument per message parameter.
    snip..."

MessageInterceptor>>doesNotUnderstand: aMessage
    mapping := messageMapping at: aMessage selector
        ifAbsent:
            ["We don't intercept this message, let the tracedObject handle it"
            ^aMessage sendTo: tracedObject].
    ^mapping valueWithArguments: {tracedObject} , aMessage arguments

たとえば、次のように使用します。

| interceptor |
interceptor := MessageInterceptor on: ObjectA interceptMessages:
    ({#new -> [:class | ObjectTracer on: class new]} as: Dictionary).
[Smalltalk globals at: #ObjectA put: interceptor.
"insert the code you want to test here"
ObjectA new yourself]
    ensure: [interceptor xxxUnTrace].
于 2012-12-09T16:06:47.737 に答える
1

オブジェクトが理解できるメソッドは、そのオブジェクトのクラスに格納されます。インスタンスの作成をオーバーライドする場合は、クラスのクラス、つまりそのメタクラスで操作したクラスに送信された#newメソッド

meta := ObjectA class.

メタクラスについては、CSE 341:Smalltalkクラスとメタクラスを参照してください。

クラス(メタクラス)のクラスを含む各クラスは、インスタンスが理解できるメッセージをメソッドディクショナリに格納します。Pharoでは、methodDictと呼ばれるインスタンス変数です。オブジェクトがメッセージを受信できるようにする場合は、メッセージ送信の結果として実行されるCompiledMethodをそのディクショナリに挿入する必要があります。Smalltalkのクラスには、CompiledMethodsをクラスにインストールするために使用できる便利なコンパイルメソッドがあります。

ObjectA 
    compile: 'new
        ^ObjectB new'
    classified: 'instance creation'

ObjectAがすでに#newメソッドを定義している場合、これはそれをオーバーライドします。後で復元できるように保存するには、古いCompiledMethodをキャッシュする必要があります。

実生活では、ここで達成しようとしていることにメソッドラッパーを使用します。WrapperstotheRescueをご覧ください

于 2017-02-12T20:04:05.040 に答える
0

私がたまたま開いている現在のMoose(Pharo)イメージには、171個のnewの実装と、1207個のinitializeの実装があります。これは、newよりもinitializeをオーバーライドする必要がある可能性がはるかに高いことを示しています。それらを閲覧すると、newをオーバーライドしたいという一般的な出来事が次のように見つかります。

  • 抽象クラス、私のサブクラスのみを作成する
  • シングルトン、代わりにuniqueInstanceを呼び出します
  • デフォルト値で作成
  • valueobject
  • 他の方言との互換性
于 2012-12-09T16:53:01.603 に答える
0

ObjectAクラス>>newを実装するだけでよいように思えます。あなたはこのようなことをすることができます:

new
  inst := self basicNew.
  ^ ObjectB wrapping: inst
于 2012-12-10T00:07:10.897 に答える