[squeak-dev] what is a transparent proxy? (was: The Inbox: Tools-ct.1101.mcz)

Chris Muller asqueaker at gmail.com
Fri Jan 14 05:59:05 UTC 2022


Hi Christoph,

> I am aware of two implementation strategies for proxies:
>
> 1. Transparent proxies/dynamic forwarding:
>
> ProtoObject subclass: #MyProxy1
> instanceVariableNames: 'object'
> classVariableNames: ''
> poolDictionaries: ''
> category: ''
>
> MyProxy1 >> doesNotUnderstand: aMessage
> ^ aMessage sendTo: object
>
> (aka "transparent proxies" or "dynamic forwarding")

Yes, but this is a massive over-simplification.  Doing _only_ this
would not come close to succeeding.  Virtually none of our code is
proxy aware.  The Symbol>>#= example is just one of our many.

BTW, the traditional name from the GoF book published in the 1990's
for the above description is simply, "Proxy".

> Additionally, you can insert any custom logic, e.g., treat certain messages in a special way, do logging, lazy initialization of the object, or anything else.
> If you do not want to follow the proxy's forwarding logic but look into the private state of the proxy instance itself, you would use mirror primitives, i.e., "thisContext objectSize: myProxy" rather than "myProxy size".

Right.  So I may not be fully aware what is meant by a "transparent"
proxy.  I thought it meant you don't have to acknowledge the
possibility of a Proxy in the code, but what you describe above is
code that *is* aware of a possible Proxy instance.  You can get a
high-percentage of transparency, but it is unavoidable in lower-level
code.

> It is important to note that one should do this rarely because any overuse of mirror primitives prevents developers from customizing the behavior.
>
> I have used this kind of proxies in some projects and my overall experiences are pretty positive so far. Nevertheless, here are some limitations with this approach:
>
> - ProtoObject is still not yet an empty class. For instance, stuff such as #doOnlyOnce: or #scaledIdentityHash should be implemented on Object only. We should continue work on this in the Trunk. You can mitigate this by redefining these messages in your proxy and forwarding them yourself.

It would arguably be a more elegant way of organizing code, but not much else.

> - Some selectors, such as #class or #==, are special selectors and inlined by the compiler so that the bytecode does not actually trigger a method lookup. If performance did not matter, I would vote for disabling the inlining by default to resolve this limitation. See: http://lists.squeakfoundation.org/pipermail/squeak-dev/2021-November/217060.html

Hear hear!  But, even that still won't be enough for fully 100%
"transparent" proxies.  Keep pressing on your applications, you'll
find them..  :)

> - Primitive methods do not resolve proxies automatically, i.e., #(1 2 3) at: (MyProxy1 for: 2) would have the primitive failed. My mitigation for this problem was to define an exclusion list for certain classes that should never be wrapped into a proxy, but this is not an ideal solution,

My mitigation strategy was a simple "yourself" on the end.  It
instantly gives away to future developers familiar with writing
proxy-aware code.  It seems like you're willing to go through to avoid
that.

> of course. If the performance overhead is slow, I would support the introduction of a new pattern in the Trunk that tries to unwrap any proxy if a primitive failed. For instance, Object >> #at: could use a mirror primitive to find out whether the primitive failed for a proxy and then retry with "self at: index yourself" or something similar. I would actually love this to upgrade the potential of proxies to certain degree. :-)

Now you're talkin'!  :-)  Proxy-aware code!!

> 2. Intransparent proxies:
>
> You derive from Object or any domain-specific class and override/reimplement every relevant message yourself, for instance:
>
> MyProxy2 >> #size
>     ^ object size
>
> The benefit is more control over the forwarded messages, but the disadvantages include the need to reimplement a potentially large protocol from all superclasses as well as the target object's class and maintain this list as both protocols change over time. This makes it less appealing and looks "unclean" and "dirty" to me.
>
> If I understand you correctly, Magma currently uses intransparent proxies? :-)

No, of course not.  Magma supports _any_ domain that is totally
unaware of Magma's existence.  Like, Morphs, for example.  It uses
what you described as "transparent proxies", above, but as I
mentioned, I have been through enough Magma applications to have
uncovered several corner cases where such proxies are not transparent
at all.  Most are due to the inlined messages you mentioned, but not
all.

Best,
  Chris


More information about the Squeak-dev mailing list