2013-04-12 23 views
5

Sto cercando di capire meglio il riflesso in Smalltalk. Sto usando l'ultima versione di Squeak (v4.3). Voglio intercettare ogni messaggio inviato a istanze di una delle mie classi. Supponevo di poter ignorare il metodo ProtoObject>>withArgs:executeMethod ma Stéphane Ducasse mi ha spiegato che per ragioni di prestazioni, questo metodo non è utilizzato (questo è il mio riassunto della sua risposta). Quale metodo devo sovrascrivere/come potrebbe intercettare i messaggi inviati?Messaggi di intercettazione in squittio

Ecco il codice del mio tentativo:

Object subclass: #C 
    instanceVariableNames: 'i' 
    classVariableNames: '' 
    poolDictionaries: '' 
    category: 'CSE3009'. 

C class compile: 'newWithi: anInt 
    ^(self new) i: anInt ; yourself.'. 

C compile: 'withArgs: someArgs executeMethod: aMethod 
    Transcript show: ''Caught: ''. 
    ^super withArgs: someArgs executeMethod aMethod.'. 

C compile: 'foo: aText 
    Transcript show: aText. 
    Transcript show: i. 
    Transcript cr.'. 

C compile: 'i: anInt 
    i := anInt.'. 

o := C newWithi: 42. 
o foo: 'This is foo: '. 

L'esecuzione di questo intero pezzo di rendimenti codice:

This is foo: 42 

Quando mi piacerebbe avere:

Caught: This is foo: 42 
+0

L'ultima versione rilasciata di Squeak è 4.4. –

risposta

5

Non c'è modo integrato per intercettare messaggi in oggetti del genere. Ci sono due modi in cui usiamo comunemente per fare questo tipo di trucco.

Innanzitutto, è possibile creare un oggetto wrapper che risponde a doesNotUnderstand :. Questo oggetto solitamente ha un valore nullo per la superclasse, quindi non eredita alcun metodo di istanza da Object. TheNotUnderstand: handler delegherebbe tutti i suoi messaggi all'oggetto di destinazione. Ha la possibilità di eseguire il codice prima e dopo la chiamata. Tutti i riferimenti all'oggetto originale ora puntano al nuovo oggetto "proxy". I messaggi su se stessi non verrebbero intercettati e il proxy avrebbe bisogno di verificare gli oggetti che restituiscono se stessi e modificare invece l'oggetto restituito come proxy.

Il secondo approccio consiste nell'utilizzare un meccanismo denominato Wrapper di metodo. Il metodo Wrapper consente di sostituire tutti i metodi in un set di classi con metodi che eseguono altre operazioni prima e dopo aver chiamato il metodo originale. Questo approccio può fornire risultati abbastanza apparenti e intercetta tutti i messaggi, inclusi quelli inviati a se stessi.

MethodWrappers è disponibile per VisualWorks e VASmalltalk. Credo che sia disponibile anche per Squeak e Pharo ma non sono positivo.

+1

Esistono diverse implementazioni di 'MethodWrapper' per Squeak o Pharo – Tobias

+0

Grazie per la risposta, ma sono un po 'sorpresa: non potrò cambiare la semantica di un metodo attraverso la riflessione? (Questo è il motivo per cui ho pensato ingenuamente che potevo ignorare 'ProtoObject >> withArgs: executeMethod:'. Voglio dire, analogamente al modo in cui riesco a sovrascrivere il nuovo metodo di classe. –

+0

Mi sembra che la soluzione che usa 'doesNotUnderstand:' funziona perché il linguaggio è non tipizzato e quello 'MethodWrapper' (e altri [ObjectTracer] (http: // stackoverflow.it/questions/888900/in-squeak-how-to-wrap-every-method-send)) è un'implementazione della soluzione con 'doesNotUnderstand:'. –

1

Le tre tecniche principali sono:

  • proxy dinamici
  • Metodo involucro
  • strumentazione Bytecode

Per un buon confronto di tutti i possibili approcci, dare un'occhiata a "Evaluating Message Passing Control Techniques in Smalltalk" di Stephane Ducasse (lo conosci già, a quanto pare).

Di interesse è anche "Smalltalk: A Reflective Langauge" di F. Rivard, che mostra come implementare pre e post-condizioni utilizzando la riscrittura bytecode. Questa è anche una forma di intercettazione.

+0

Grazie a @ewernli, in realtà li ho già letti ma non portano soluzioni dirette al mio problema ... –