[squeak-dev] #species vs OrderedColleciton

Levente Uzonyi leves at caesar.elte.hu
Tue Dec 27 19:35:03 UTC 2016


On Tue, 27 Dec 2016, Tobias Pape wrote:

>
> On 27.12.2016, at 18:01, Levente Uzonyi <leves at caesar.elte.hu> wrote:
>
>> On Tue, 27 Dec 2016, Tobias Pape wrote:
>> 
>>> 
>>> On 27.12.2016, at 17:45, Levente Uzonyi <leves at caesar.elte.hu> wrote:
>>> 
>>>> On Tue, 27 Dec 2016, Tobias Pape wrote:
>>>>> On 25.12.2016, at 17:09, Levente Uzonyi <leves at caesar.elte.hu> wrote:
>>>>>> Hi All,
>>>>>> We had a discussion[1] about #species, in the context of Sets and IdentitySets, and its multiple roles which it cannot fulfill[2].
>>>>>> A similar issue arises in case of OrderedCollection and its subclasses, but with a smoother resolution, because an OrderedCollection is always an acceptable result (for #collect:).
>>>>>> So, I suggest we should change OrderedCollection >> #collect: to always return an OrderedCollection. This change obviously would not affect OrderedCollection, but we already have the same override in SortedCollection.
>>>>>> Example:
>>>>>> Currently the following raises and error:
>>>>>>
>>>>>> 	(FloatCollection withAll: #(1 2 3)) collect: #asString
>>>>>> Of course, #collect:as: works as expected:
>>>>>>
>>>>>> 	(FloatCollection withAll: #(1 2 3)) collect: #asString as: OrderedCollection
>>>>>> 	"==> an OrderedCollection('1.0' '2.0' '3.0')"
>>>>>> So, why not make #collect: behave the same way?
>>>>>> This change would make #species not being used in #collect:, which is similar to the solution we have in Set and subclasses.
>>>>>> Currently #select: and #copyEmpty also use #species, but no class implements #species in the hierarchy. So, changing #species to return OrderedCollection would have unwanted side effects. (This also shows that #species doesn't solve anything here.)
>>>>>> Any objections?
>>>>> Just a question for clarification, would
>>>>>
>>>>> 	(FloatCollection withAll: #(1.0 2.0 3.0)) collect: [:ea | ea sqrt]
>>>>> result in a FloatCollection or in an OrderedCollection?
>>>> An OrderedCollection of course. #collect: would always return an OrderedCollection.
>>> 
>>> Ok, so to make good use of FloatCollections in the first place i would have to always use collect:as: to _stay within_ the class? I somehow do not like that :(. I'd rather have to stay
>> 
>> So you'd rather have the errors?
>
> Yes, sure. FloatCollection withAll: #('1.0' '2.0' '3.0') raises an error too. The result is just not fitted for the storage.
>
>> 
>>> as much as possible with the closure property for large parts of the collection API.
>> 
>> What's the "closure property"?
>
> Roughly, "If you apply Operation x to a thing y, and the result always stays within the domain of y, then (the domain of) y is closed under x".
>
> Examples: The real numbers are closed under addition, as are the integers. 
> But while the real numbers are closed under division, integers are not.
>
> In scheme, 'cons' is closed under 'map'.
>
> Most of our collections are closed under #collect:, #select:, #reject:.

(Have you read the thread about IdentitySet >> #collect: I linked in my 
original post?)
#select: and #reject: are very different from #collect:. Ignoring this 
fact was one of the sources of the current problems with #species.
When you #select: or #reject: from a collection, you can't transform the 
objects, only filter them.
When you #collect: from a collection, you can't filter the objects, but 
you can transform them to anything.

So, what makes you think the result of #collect:'s argument should be the 
same kind as its argument?

>
>> 
>>> 
>>> Whats wrong with species -> class, and collect: staying within the class?
>> 
>> Did you try the example in my first post?
>> 
>> species -> class would do nothing, because, as I mentioned in my original post, species is not overridden anywhere in the class hierarchy.
>
> I meant retaining  the species -> class that is inherited from object.

Oh. It's wrong, because, as my example showed, it doesn't work. Here's 
another one in case you think it's only about #asString:

 	(#(1 2 3) as: FloatCollection) collect: #asPoint

>
>> 
>>> We got several specialized collections, I don't want a buch of collectFloat: collectInteger: collectShortPoint: for each and every class.
>> 
>> Why would such methods ever appear? Have you seen anything like that anywere?
>
> Because I assume that 'closed' usage of collect is the more common usage[1], and sooner or later,
> we would have FloatCollection>>collectFloat: next to collect:, and SortedCollection>>collectSorted: next to collect:, and 
> GraphicSymbol probably would break with just few people noticeing.

Uh. The way GraphicSymbol is implemented is a plain mistake. Subclassing 
any Collection for no reason is a big no-no. Also, it's a variable 
subclass for absolutely no reason; the slots are never used.
Fortunately that class is not used at all. To be removed.

>
> And why should a WeakOrderedCollection return something 'strong' after a collect?

The answer is the same as to the same question about WeakSet: the 
collected objects may get GC'd before #collect: returns.

>
> Also, the symmetry between FloatArray and FloatCollection would break:
>
> (FloatCollection withAll: #(1.0 2.0 3.0)) collect: [:ea | ea sqrt]  "a FloatCollection(1.0 1.4142135381698608 1.7320507764816284)"
> (FloatArray withAll: #(1.0 2.0 3.0)) collect: [:ea | ea sqrt] "a FloatArray(1.0 1.4142135381698608 1.7320507764816284)"

Another thing to fix. ;)

Levente

>
> Best regards
> 	-Tobias
>
>
> [1]: maybe except for #asString, but that's debugging. Maybe we should introduce Collection>>#allAsString ?


More information about the Squeak-dev mailing list