This document discusses proxy objects in Smalltalk. It begins by defining a proxy as a surrogate or placeholder that controls access to another target object. It then describes different approaches to implementing proxies and their limitations, such as issues with traditional approaches that use #doesNotUnderstand:. The document proposes an alternative "ghost model" using #cannotInterpret: to intercept all messages in a uniform way while keeping proxies and handlers separate. It explains how this approach works and advantages it has over traditional proxies. The document also discusses extending this approach to proxy classes and methods.
2. What is a proxy?
2
A proxy object is a surrogate or
placeholder that controls access to
another target object.
Monday, August 22, 2011
3. Glossary
Target: object to proxify.
Client: user of the proxy.
Interceptor: object that intercepts message
sending.
Handler: object that performs a desired
action as a consequence of an interception.
3
Monday, August 22, 2011
5. With or without
Object replacement?
In proxies with object replacement
(#become:), the target object is replaced by a
proxy.
Proxies without object replacement are a
kind of factory.
5
Monday, August 22, 2011
6. With or without
Object replacement?
In proxies with object replacement
(#become:), the target object is replaced by a
proxy.
Proxies without object replacement are a
kind of factory.
5
Monday, August 22, 2011
7. Traditional proxy
implementations
6
Usage of a minimal object together with an implementation of a
custom #doesNotUnderstand
doesNotUnderstand:
executeBeforeHandling
executeAfterHandling
target
Proxy
identityHash
pointersTo
nextObject
...
ProtoObject
Monday, August 22, 2011
8. 7
We are going to play
a little game...
Monday, August 22, 2011
9. 8
Are both prints in Transcript the same or not?
Monday, August 22, 2011
10. 8
Are both prints in Transcript the same or not?
Conclusion: methods understood are NOT intercepted.
Is that bad?
Monday, August 22, 2011
11. 8
Are both prints in Transcript the same or not?
Conclusion: methods understood are NOT intercepted.
Is that bad?
Different execution paths Errors difficult to find
Monday, August 22, 2011
12. 9
Do we want the regular #doesNotUnderstand
or to intercept the message?
Monday, August 22, 2011
13. 10
Do we want the regular #doesNotUnderstand
or to intercept the message?
Monday, August 22, 2011
14. 11
I wanted the normal #doesNotUnderstand!!!
Monday, August 22, 2011
15. 12
I wanted the normal #doesNotUnderstand!!!
Monday, August 22, 2011
16. Problems
#doesNotUnderstand: cannot be trapped like a
regular message.
Mix of handling procedure and proxy
interception.
Only methods that are not understood are
intercepted.
No separation between proxies and handlers
13
This approach is not stratified
Monday, August 22, 2011
20. Used hooks
Object replacement (#become:)
Change an object’s class (#adoptInstance:)
Objects as methods (#run:with:in:)
Classes with no method dictionary
(#cannotInterpret:)
17
Monday, August 22, 2011
22. Objects as methods
19
The VM sends #run: aSelector with: anArray in: aReceiver
Monday, August 22, 2011
23. Objects as methods
19
The VM sends #run: aSelector with: anArray in: aReceiver
So.....We can implement in Proxy:
Monday, August 22, 2011
24. CLasses with no
method dictionary
20
aProxy
aProxy username
1: #username send
methodDict := nil
ProxyTrap
cannotInterpret: aMessage
Proxy
Object
2: #aProxy lookup
3: Since the method dictionary was nil,
the VM sends #cannotInterpret to
the receiver but starting the lookup in the superclass
4: #cannotInterpret: lookup
References
instance of
message send
lookup
subclass
Monday, August 22, 2011
32. aProxy
aProxy username
1: #username send
methodDict := nil
ProxyTrap
cannotInterpret: aMessage
Proxy
Object
2: #aProxy lookup
3: Since the method dictionary was nil,
the VM sends #cannotInterpret to
the receiver but starting the lookup in the superclass
4: #cannotInterpret: lookup
References
instance of
message send
lookup
subclass
How it works?
23
Monday, August 22, 2011
33. aProxy
aProxy username
1: #username send
methodDict := nil
ProxyTrap
cannotInterpret: aMessage
Proxy
Object
2: #aProxy lookup
3: Since the method dictionary was nil,
the VM sends #cannotInterpret to
the receiver but starting the lookup in the superclass
4: #cannotInterpret: lookup
References
instance of
message send
lookup
subclass
How it works?
23
Monday, August 22, 2011
34. aProxy
aProxy username
1: #username send
methodDict := nil
ProxyTrap
cannotInterpret: aMessage
Proxy
Object
2: #aProxy lookup
3: Since the method dictionary was nil,
the VM sends #cannotInterpret to
the receiver but starting the lookup in the superclass
4: #cannotInterpret: lookup
References
instance of
message send
lookup
subclass
How it works?
23
Monday, August 22, 2011
35. aProxy
aProxy username
1: #username send
methodDict := nil
ProxyTrap
cannotInterpret: aMessage
Proxy
Object
2: #aProxy lookup
3: Since the method dictionary was nil,
the VM sends #cannotInterpret to
the receiver but starting the lookup in the superclass
4: #cannotInterpret: lookup
References
instance of
message send
lookup
subclass
How it works?
23
Monday, August 22, 2011
36. aProxy
aProxy username
1: #username send
methodDict := nil
ProxyTrap
cannotInterpret: aMessage
Proxy
Object
2: #aProxy lookup
3: Since the method dictionary was nil,
the VM sends #cannotInterpret to
the receiver but starting the lookup in the superclass
4: #cannotInterpret: lookup
References
instance of
message send
lookup
subclass
How it works?
23
Monday, August 22, 2011
37. aProxy
aProxy username
1: #username send
methodDict := nil
ProxyTrap
cannotInterpret: aMessage
Proxy
Object
2: #aProxy lookup
3: Since the method dictionary was nil,
the VM sends #cannotInterpret to
the receiver but starting the lookup in the superclass
4: #cannotInterpret: lookup
References
instance of
message send
lookup
subclass
How it works?
23
Proxy >>
Monday, August 22, 2011
38. aProxy
aProxy username
1: #username send
methodDict := nil
ProxyTrap
cannotInterpret: aMessage
Proxy
Object
2: #aProxy lookup
3: Since the method dictionary was nil,
the VM sends #cannotInterpret to
the receiver but starting the lookup in the superclass
4: #cannotInterpret: lookup
References
instance of
message send
lookup
subclass
How it works?
23
Proxy >>
SimpleForwarderHandler >>
Monday, August 22, 2011
39. 24
Traditional Ghost
#doesNotUnderstand:
cannot be trapped like a
regular message.
#cannotInterpret: is
trapped like a regular
message.
Mix of handling
procedure and proxy
interception.
No mix of handling
procedure and proxy
interception.
Only methods that are
not understood are
intercepted.
“All” methods are
intercepted.
No separation between
proxies and handlers.
Clear separation between
proxies and handlers.
Monday, August 22, 2011
41. Methods not intercepted
26
1) Optimizations done by the Compiler
2) Special shortcut bytecodes between Compiler and VM
2.1) Methods NEVER sent: #== and #class
2.2) Methods that may or may not be executed depending
on the receiver and arguments: e.g. in ‘1+1’ #+ is not
executed. But with ‘1+$C’ #+ is executed.
2.3)Always executed, they are just little optimizations.
Examples #new, #next, #nextPut:, #size, etc.
Monday, August 22, 2011
42. Methods not intercepted
26
1) Optimizations done by the Compiler
2) Special shortcut bytecodes between Compiler and VM
2.1) Methods NEVER sent: #== and #class
2.2) Methods that may or may not be executed depending
on the receiver and arguments: e.g. in ‘1+1’ #+ is not
executed. But with ‘1+$C’ #+ is executed.
2.3)Always executed, they are just little optimizations.
Examples #new, #next, #nextPut:, #size, etc.
Monday, August 22, 2011
43. Methods not intercepted
26
1) Optimizations done by the Compiler
2) Special shortcut bytecodes between Compiler and VM
2.1) Methods NEVER sent: #== and #class
2.2) Methods that may or may not be executed depending
on the receiver and arguments: e.g. in ‘1+1’ #+ is not
executed. But with ‘1+$C’ #+ is executed.
2.3)Always executed, they are just little optimizations.
Examples #new, #next, #nextPut:, #size, etc.
Monday, August 22, 2011
54. Proxy for methods
28
Just handling #run:with:in correctly is enough to also
intercept method execution.
Regular message
Method execution
Monday, August 22, 2011
57. More features
Low memory footprint.
Compact classes.
Store the minimal needed state.
Easy debugging.
Custom list of messages.
30
Monday, August 22, 2011
58. Conclusion
31
With a little bit of special support from
the VM (#cannotInterpret hook), we
can have an image-side proxy solution
much better than the classic
#doesNotUnderstand:
Monday, August 22, 2011
59. Future work
Experiment with immediate proxies
(memory address tag) in VM side.
Think how to correctly intercept non-
executed methods.
32
Monday, August 22, 2011