On Fri, 23 Nov 2018, Chris Muller wrote:
Hi Eliot,
Basically, it comes down to Proxy's. I want them to work better in Squeak. But every time we put another send to #class or #== in an implementation of #=, since those methods are inlined, they're too brittle to work with Proxy's. This causes hard-to-trackdown bugs in applications and mini-messes to deal with them since the app is forced to change its code to become "aware" of potential Proxy'iness of an object before comparing it with #=.
The disease is the inclining of #class and #==, not the use of these in comparison methods. In the VisualWorks vm I implemented a command-line/image header switch that enabled/disabled this inlining. It is easy to implement the same thing on Cog.
If we did, then these methods would not be inlined if the flag is enabled, on a per-image basis.
Having consistent send properties among all messages would be cool. Having said that, I do like performance, and there aren't that many in-lined messages, and experience has trained me to recognize when I use them and pay attention to the Proxy-dynamics. A "global switch" approach would force the entire image to incur the overhead, even for non-DB objects like the Morphs of the UI. A simple #yourself strategically sprinkled here or there is not such a huge deal for me, except that a lot of them could be trivially eliminated by nothing more than a flexibility from my peers about their interpretations of "equivalence".
Perhaps if the method were called #ensureNonProxiedReceiver instead of #yourself, your peers would know why it is there.
An alternative is Marcus Denker’s Opal compiler for Pharo which compiles #class and #== to normal sends, avoiding the inlined special selector bytecodes for these sends. That’s arguably an even better solution, because it retains the ability to inline. Although the mirror methods objectClass: and object:eqeq: can be used, with more overhead.
In any case, instead of proposing to change a natural and comprehensible idiom, we can instead evolve the implementation to meet our needs.
Smalltalk is supposed to be about messages, not types. So why shouldn't we let the _messages_ determine equivalence instead of enforcing conformance to some specific "type"? You know we already have several classes that use #isKindOf: rather than == otherObject class. So, I think my proposal is natural and comprehensible too, especially. from the aspect that it avoids the real-world bugs that can sometimes seem incomprehensible.
"foo isKindOf: Bar" is not a substitute for "foo class == Bar". "foo isMemberOf: Bar" is what you should use instead (if you really want worse performance :)).
Levente
This is no surprise, since writing a send to #== instead of #= for no more than "performance" is actually breaking encapsulation in the firs t place...
There is an easy solution. When writing #= and #hash implementations, use (#species or #xxxClass or #isKindOf: instead of #class) and #= instead #==. So, for example, Eliot, I want to upgrade your new Message>>#= to something like:
= anObject ^self xxxClass = anObject xxxClass and: [selector = anObject selector "selector lookup is by identity" and: [lookupClass = anObject lookupClass and: [args literalEqual: anObject arguments]]]
Or #species or #isKindOf:, like we do in many other methods. Now the method is Proxy-compatible.
What do you think?
I think it is wrong. xxxClass is a horrible hack that should be banished ASAP.
Other than it having an unattractive name, what is wrong about it? Smalltalk is supposed to be a full computer implemented in itself, but you want to introduce a new VM feature and a new global setting that slows down the entire image and even has to be reckoned with all the way out in the Linux scripts (for cmdline arg), all just to avoid writing #= instead of #== in a few places? :(
- Chris