My 2 cents. On 16 February 2010 19:49, Martin McClure <martin@hand2mouse.com> wrote:
Stéphane Ducasse wrote:
there is a really nice discussion on supporting (not having an inspector breaking) when browsing proxy. Can you have a look?
Thanks for the summary.
At GemStone we work a lot with our own proxies which represent objects in another VM. We also have our own inspectors and debuggers to inspect these effectively. Over the years I've made a lot of design mistakes in this area and have had to fix them. Along the way I have come to some definite opinions about how inspectors and proxies should interact:
* When inspecting a proxy, the proxy should look to the user like a proxy, not like the object being proxied. To do otherwise causes great confusion for the person using the inspector. Ideally, an inspector offer the option to have multiple views of the same object, a basic view which shows the low-level structure and possibly higher-level views which show the logical structure of objects which the inspector knows how to do special things for. So for instance sets show their real instvars (tally, array) for the basic view but their elements and size for a logical view. For proxies the higher-level view might be to inspect the object being proxied.
+1. Inspectors should display proxies, not proxied objects.
* Inspectors should never assume that the object being inspected can respond to *any* message. In the case of Pharo it's probably OK to assume that all objects inherit from ProtoObject, but IMO if debugging tools are designed correctly ProtoObject should not be needed and proxy classes can inherit directly from nil and implement no methods other than #doesNotUnderstand:. To achieve this an inspector should send no messages to an object until it knows something about how that object will respond to the message. It is *not* safe to send a not-understood message and catch the exception, because a proxy's response to a not-understood message may change the state of the proxy or other objects in the local or remote system, and debugging tools should only change the state of the system when explicitly told to. To achieve this you need a primitive to determine the "real" class of an object without sending that object a message. I don't know if Pharo currently has this, but it's very useful, and extremely simple to implement. VW has a minimal reflection API that includes this, and GemStone recently added a fairly complete reflection API that allows determining class and size of an object as well as getting setting values of its instvars all without sending the object any messages. This reflection facility is not really object-oriented, since it examines and changes state of objects without sending the object messages, breaking encapsulation. However, this is useful, and I don't think it's any worse than the existing messages like #instVarAt:(put:) which fulfill the same function. These existing messages also break encapsulation and are at such a different level of abstraction from the rest of the object's protocol that they aren't really good object design either.
* Once the inspector knows what the class of the inspected object is, it can send messages to the class (which even for proxy classes inherits from Behavior) to determine what inspecting facilities to offer. Object class would answer only the basic inspector, Set class would override this to add Set-specific inspector(s), Dictionary class would override again to replace the Set-specific inspectors with Dictionary ones, and so on.
Some of this modularity is already in the new inspector, but the important notion that is missing is "Send *no* messages to an object until you know what kind of object you're dealing with".
-1 here. I don't like breaking encapsulation. You gain nothing from revoking control from the object how to expose its own contents. Let me illustrate why: Suppose you want to print ivars of a proxy object without sending any messages to it. Okay, by using a primitive (which breaks encapsulation) you getting an object's class. And now you can send messages to that class.. Which is fine, except on some extreme cases one could have own class hierarchy, which not inherits from Behavior. So, you introducing a limiting factor along the way... Now, suppose that by doing such trickery you extracted some object from one of inspected object ivars. But hey, extracted object can be in own turn a proxy, and printing it may cause a side effects! Now, how you suppose to print anything without sending any message? A deadlock. So, since you can't avoid sending a message, then why doing this black voodo at all? Why not just establish a system-wide minimal protocol and say that all objects in system should respond with #mirror message, or #readOnlyMirror, if you like? Then, a) you don't have to break encapsulation b) any object could decide by itself, in what fashion to expose own contents. Problem solved.
Regards,
-Martin
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
-- Best regards, Igor Stasenko AKA sig.