On Dec 4, 2009, at 9:12 30AM, Igor Stasenko wrote:
2009/12/4 Lukas Renggli <renggli@gmail.com>:
Actually the code can be further optimized:
Dictionary>>keys "Answer a Set containing the receiver's keys."
| result container | result := Set basicNew setTally: tally array: array copy. container := result array. 1 to: container size do: [ :index | (container at: index) ifNotNil: [ :assoc | container at: index put: assoc key ] ]. ^ result
This is roughly 22 times faster than the current implementation, and 5 times faster than the squeak implementation.
The system doesn't seem to break with this change :-)
except that it breaking encapsulation. Thus i vote -1 for this kind of optimization :)
You could also achieve the same performance by writing the method (returning an array) | result currentIX | result := Array new: tally. currentIX := 1. 1 to: array size do: [:ix | (array at: ix) ifNotNil: [:assoc | result at: currentIX put: assoc key. currentIX := currentIX +1]]. ^result Which is, unless you consider using at:put: and expecting an Array of size n to hold n elements, not breaking encapsulation. Though, the block creation overhead of using keysDo (which is the main reason for the performance difference seen between the two) should, if I've understood Eliot correctly, go away with a stack-based vm. While on the topic of the Set hierarchy, is it just me, or is the Keyed* versions a mistake? Giving a block that computes a key means the collection either needs to: - Know about what type of objects is put into it, in which case you break encapsulation. and it would likely be better to just implement hash/= for those types of objects. - Only use info available of Object, in which case you're not very likely to end up with much better hash functions than scaledIdentityHash anyways. Cheers, Henry