2013-04-12 14 views
5

Próbuję zrozumieć lepsze odbicie w Smalltalk. Używam najnowszej wersji Squeak (v4.3). Chcę przechwycić każdą wiadomość wysłaną do instancji jednej z moich klas. Sądziłem, że mogę zastąpić metodę, ale Stéphane Ducasse wyjaśnił mi, że ze względu na wydajność ta metoda nie jest używana (to jest moje podsumowanie odpowiedzi). Którą metodę należy przesłonić/jak mogę przechwycić wysłane wiadomości?Przechwytywanie wiadomości w pisku

Oto kod mojego próba:

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: '. 

Wykonywanie cały ten kawałek rentowności kod:

This is foo: 42 

Kiedy chciałbym posiadać:

Caught: This is foo: 42 
+0

Najnowsza wersja Squeaka to 4.4. –

Odpowiedz

5

Nie ma to wbudowany sposób przechwytywania wiadomości do takich obiektów. Istnieją dwa sposoby, w jaki zwykle używamy tego rodzaju sztuczki.

Najpierw można utworzyć obiekt opakowania, który odpowiada na wartość doesNotUnderstand :. Ten obiekt zwykle ma zero dla superklasy, więc nie dziedziczy żadnych metod instancji z Object. Program doNotUnderstand: handler przekaże wszystkie swoje wiadomości do obiektu docelowego. Ma możliwość wykonania kodu przed i po wywołaniu. Wszystkie odniesienia do oryginalnego obiektu wskazywałyby teraz na nowy obiekt "proxy". Wiadomości do siebie nie zostałyby przechwycone, a proxy musiałoby przetestować obiekty zwracające wartość self i zamiast tego zmienić zwracany obiekt na proxy.

Drugim podejściem jest użycie mechanizmu o nazwie Owijarki metod. Metoda Owijarki metod pozwala na zastąpienie wszystkich metod w zestawie klas metodami wykonującymi inne operacje przed i po wywołaniu oryginalnej metody. Takie podejście może zapewnić dość bezsensowne wyniki i przechwytuje wszystkie wiadomości, w tym te wysyłane do siebie.

MethodWrappers jest dostępny dla VisualWorks i VASmalltalk. Uważam, że jest on również dostępny dla Squeak i Pharo, ale nie jestem pozytywny.

+1

Istnieje kilka implementacji 'MethodWrapper' dla Pisk lub Pharo – Tobias

+0

Dziękuję za odpowiedź, ale jestem trochę zaskoczony: czy nie będę w stanie zmienić semantyki wywołania metody przez odbicie? (Dlatego naiwnie pomyślałem, że mogę zastąpić 'ProtoObject >> withArgs: executeMethod:'. Mam na myśli, podobnie jak sposób, w jaki mogę nadpisać nową metodę klasy. –

+0

Wydaje mi się, że rozwiązanie, które używa 'doesNotUnderstand:' działa ponieważ język jest niezaszyfrowany i że 'MethodWrapper' (i inny [ObjectTracer] (http: // stackoverflow.com/questions/888900/in-squeak-how-to-wrap-every-method-send)) jest implementacją rozwiązania z 'doesNotUnderstand:'. –

1

Trzy główne techniki są:

  • Dynamiczne proxy
  • Metoda wrapper
  • oprzyrządowanie Bytecode

Dla dobrego porównania wszystkich możliwych podejść, przyjrzeć się "Evaluating Message Passing Control Techniques in Smalltalk" Stephane Ducasse (najwyraźniej już go znasz).

Interesujący jest także "Smalltalk: A Reflective Langauge" autorstwa F. Rivarda, który pokazuje, jak zaimplementować warunki przed i po użyciu, stosując przepisywanie bajtów. Jest to również forma przechwytywania.

+0

Dzięki @ewernli, faktycznie już je czytam, ale nie przynoszą bezpośrednich rozwiązań mojego problemu ... –