[squeak-dev] The Inbox: Tools-ct.1101.mcz
Christoph.Thiede at student.hpi.uni-potsdam.de
Wed Jan 12 13:36:45 UTC 2022
Hi Chris, hi Marcel, hi al,
> I would say that #size being an expensive operation on a collection is quite surprising and thus not foreseeable in general.
> If Magma collections require a modification, then Magma can make an extension or offer its own Magma-specific inspectors.
Chris, you could override #inspectorClass on your MagmaCollection and have it answer MagmaCollectionInspector, a subclass of CollectionInspector which overrides #labelString again. :-)
Another "hacky" solution without creating your own inspector would be a sender check in your #size implementation:
MagmaCollection >> #size
(thisContext sender receiver isKindOf: Inspector) ifTrue: [^ nil].
^ self expensiveSize
Disclaimer: This will be likely noticeably slower, of course. :-)
> I'm not sure, but Eliot says it's the way Proxy's are supposed to be done in Squeak so that ProtoObject can have no methods.
I am aware of two implementation strategies for proxies:
1. Transparent proxies/dynamic forwarding:
ProtoObject subclass: #MyProxy1
MyProxy1 >> doesNotUnderstand: aMessage
^ aMessage sendTo: object
(aka "transparent proxies" or "dynamic forwarding")
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". 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.
- 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
- 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, 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. :-)
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? :-)
Von: Squeak-dev <squeak-dev-bounces at lists.squeakfoundation.org> im Auftrag von Taeumel, Marcel
Gesendet: Mittwoch, 12. Januar 2022 09:10:54
Betreff: Re: [squeak-dev] The Inbox: Tools-ct.1101.mcz
Hi Chris, hi all --
> CollectionInspector is used for Magma's large MagmaCollections, which require a db access to retrieve the size
CollectionInspector is optimized for Smalltalk collections. That's the only thing we can guarantee. If Magma collections require a modification, then Magma can make an extension or offer its own Magma-specific inspectors. Yet, it makes sense to always look out for such external projects to not break compatibility without reason. I would say that #size being an expensive operation on a collection is quite surprising and thus not foreseeable in general.
Currently the default Inspector should not be used to look behind proxies. That's what the BasicInspector is for. If a proxy mimics morphs, than that normal inspector for such proxies should also be a MorphInspector. And so on.
Am 12.01.2022 00:52:20 schrieb Chris Muller <ma.chris.m at gmail.com>:
I am not sure whether we can (or should) make the default inspector proxy-safe. Rather, IMHO the default inspectors should handle proxies transparently and display the underlying object.
For inspecting the implementation details of proxies, we have the BasicInspector, which is almost completely proxy-safe (the only exception I am aware of is a send to #isReadOnlyObject for the window label, for which we currently do not have a mirror primitive).
Yes, in principle, it's impossible to argue against that. "Backward-compatibility" for Magma is all I've got.
> #size is a provoking message.
And #printString, #longPrintString, #perform:, #instVarNamed:, #basicSize, and all others existing sends are not? :-)
They are, but not invoked until you interact with the Inspector. Putting the #size in the title bar changes that behavior.
Also, it may be presumptuous to assume the collection being inspected is a SmalltalkCollection. CollectionInspector is used for Magma's large MagmaCollections, which require a db access to retrieve the size..
> Magma's Proxy's anyway (which don't use the mirror-primitives but the old-school Proxy pattern)
Just out of interest, how would you implement a proxy using mirror primitives? :-)
I'm not sure, but Eliot says it's the way Proxy's are supposed to be done in Squeak so that ProtoObject can have no methods.
Unfortunately, it would require rewriting a lot of low-level methods like Symbol>>#= to be (to my knowledge) non-standard Smalltalk which, realistically, is not ever going to be done, and therefore I'm doubtful the dream of "transparent proxies" will ever, uh, materialize (no pun intended! :) ), which is unfortunate because that "dream" continues to be a Magma-killer (slowly by a thousand cuts). Magma's Proxy's have worked well-enough for *applications* for many years, but lately developers seem to want "clean", "transparent" proxies and so even the standard old-school Gang-of-Four Proxy pattern remains broken since 5.3.
I hope I'm missing something and completely wrong about the above, but I don't think I am. I admit I haven't had the time or inclination to try to re-inventing Magma's proxy system just to accommodate some abstract notions of purity. I'm concerned with application of computer code to external, real-world purposes.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Squeak-dev