Hi Max,
Richard Sargent wrote:Eliot Miranda-2 wrote
On Wed, Oct 15, 2014 at 10:50 AM, Richard Sargent <
richard.sargent@
wrote:
One of the best things about Smalltalk is how easily we can say what we
mean. I think you would be better off creating a method named something
like
#hasSameEffectAs: to answer what you are presently using #= to do, and
change #= to answer the, in my opinion, more sensible "is the same as"
that
we conventionally think of #= meaning.
But that's the point. #= has to mean something and having it mean #==
isn't useful, so one has to choose some value-based semantic for
CompiledMethod>>#= and the one that's there is useful. Defining what #=
means for some value type is far easier than defining what it might mean
for something as complex as a CompiledMethod. The definition in
Squeak/Pharo has been useful to me in implementing a closure-based system,
so I'm unapologetic about the current definition. It is a good one but it
doesn't preclude defining others.
An interesting response. You ignored the point that e.g. #hasSameEffectAs:
provides greater clarity and add an argument against something I didn't say.
I also don't think defining equality for a CompiledMethod is particularly
difficult. If I were to recompile a method's source code, I would get a new
instance of a CompiledMethod that would, in my opinion, be equal to the one
already installed in the class (and perhaps cached in the VM's
optimizations). So one would be able to say that we would not replace an
existing CompiledMethod with an equal one. The current implementation of #=
has no such characteristic, since it proclaims a CompiledMethod named #a to
be equal to one named #z.
@RichardThat doesn't seem to be a good example for what your trying to say.Given...[1] SomeClass>>a "original instance" ^1[2] SomeClass>>a "recompiled instance" ^1[3] SomeClass>>z ^1...you seem to be saying that its useful to know if [1]=[2],but imply that is invalidated by [2]=[3] ?But [1]=[2] remains true, and just as useful for your example.@MaxI guess to call it a bug, you bumped into a different use casewhere [2]=[3] is problematic. Can you describe that?
Well, not problematic. Once you accept that neither selector nor class are part of a CompiledMethod it is obvious that two instances with the same byte codes produce the same hash.
The actual problem is more one of understanding and use. The following code answers a collection with the CompiledMethods Collection>>add:, Collection>>do: and Collection>>remove:ifAbsent:
Collection methods select: #isAbstract.
All three CompiledMethods are implemented as ���^ self subclassResponsibility���, so they have the same byte codes. Now, if you take that collection and make a set out of it you���ll lose Collection>>do: since #do: and #add: produce the same hash, but #remove:ifAbsent: doesn���t because the number of arguments is calculated into the hash (actually the CompiledMethod header is).
Surely the issue is that "aClass methods" should answer an IdentitySet right?
Well, in the case of my example that wouldn���t change anything. As soon as you put the methods into a set you���ll end up with less entries than before again. Selectors are unique per class anyway so I don���t quite see the benefit of using an IdentitySet over an OrderedCollection (or a Bag for that matter), except for making it more obvious that the result of the message #methods doesn���t need to be filtered further.
I should add that the code, the student who discovered the clash wrote, looked more like this:
result := Set new.
Collection methods do: [ :m |
m isAbstract ifTrue: [ result add: m ] ].
Max