<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Nov 28, 2014 at 7:42 PM, Ben Coman <span dir="ltr">&lt;<a href="mailto:btc@openinworld.com" target="_blank">btc@openinworld.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">Levente Uzonyi wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
The problem with changing #species is that it&#39;s overused. There are at least three different things it&#39;s used for in the Collection hierarchy:<br>
- the class of the object returned by #collect: (Set&#39;s subclasses are the exception since 2000 or so, except for WeakSet, but that&#39;s really strange, and should revisited)<br>
- the class of the object returned by #select: and friends<br>
- the class used for comparison of collections<br>
</blockquote>
<br></span>
So should there be #collectSpecies ?<br></blockquote><div><br></div><div>No.  That&#39;s what species was invented for in the first place.<br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Which defaults to &quot;^self species&quot; and is overidden as required.<br>
<br>
In the case of Sets, you start with an &quot;unordered collection without duplicates&quot;, but since #collect can introduce duplicates, you end up with &quot;an unordered collection with duplicates&quot; --&gt; Bag (per Dave&#39;s suggestion)<br>
<br>
So I think its reasonable that the following two snippets should produce the same result.<br>
<br>
oc := OrderedCollection newFrom: #( 1 2 3 4 5 ).<br>
(oc collect: [ :e | e even ]) occurrencesOf:  true. &quot;--&gt; 2&quot;<br>
<br>
s := Set newFrom: #( 1 2 3 4 5 ).<br>
(s collect: [ :e | e even ]) occurrencesOf:  true.  &quot;--&gt; 2&quot;<br>
<br>
<br>
which you get with the following change...<br>
<br>
Set&gt;&gt;collectSpecies<br>
        ^Bag<br>
<br>
Set&gt;&gt;collect: aBlock<br>
        | result |<br>
        result := self collectSpecies new: self size.<br>
        array do: [:each | each ifNotNil: [result add: (aBlock value: each enclosedSetElement)]].<br>
        ^ result<span class=""><br>
<br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
HashedCollection &gt;&gt; #select: uses #species. Changing IdentitySet<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
#species to return a Set would break #select:, because a ~~ b doesn&#39;t <br>
</blockquote></blockquote>
imply a ~= b. IdentitySet is the optimal class for the return value of IdentitySet &gt;&gt; #select:, because it&#39;s guaranteed to be able to hold all selected values. I think the same applies to all other kind of sets (and collections, because #select: is simply reducing the number of elements).<br>
<br>
This is not the first time this discussion comes up. There was one in 2003[1], but the thread is hard to follow. And there was one in 2009[2].<br>
I think the conclusion was that it&#39;s better to leave the method as it is, because there&#39;s no better way to do it.<br>
Sure, we could use #species in #collect:, but it would break quite a lot of stuff. For example:<br>
<br>
| k |<br>
k := KeyedSet keyBlock: [ :each | each first ].<br>
k add: #[1]; add: #[2].<br>
k collect: [ :each | each size ]<br>
</blockquote>
<br>
<br></span>
That works with the above change to produce --&gt; a Bag(1 1)<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Currently this snippet returns &quot;a Set(1)&quot;. Using #species in #collect: (via #copyEmpty) one would get an error, because SmallInteger does not understand #first. Changing the #species of KeyedSet would break #select:.<br>
<br>
So IMHO when you #collect: from a set, you should always use #collect:as:. Here is a (partial) list of methods which send #collect: to a Set:<br>
<br>
Categorizer &gt;&gt; #changeFromCategorySpecs:<br>
ClassFactoryForTestCase &gt;&gt; #createdClassNames<br>
Dictionary &gt;&gt; #unreferencedKeys<br>
MCDependencySorterTest &gt;&gt; #assertItems:orderAs:<u></u>withRequired:toLoad:<u></u>extraProvisions:<br>
MessageNode &gt;&gt; #analyseTempsWithin:rootNode:<u></u>assignmentPools:<br>
MethodNode &gt;&gt; #<u></u>referencedValuesWithinBlockExt<u></u>ent:<br>
SetTest &gt;&gt; #testCollect<br>
SetWithNilTest &gt;&gt; #runSetWithNilTestOf:<br>
<br>
There are probably many more, but we should fix all of them. A static analyzer could help a lot.<br>
<br>
Levente<br>
<br>
[1] <a href="http://lists.squeakfoundation.org/pipermail/squeak-dev/2003-February/052659.html" target="_blank">http://lists.squeakfoundation.<u></u>org/pipermail/squeak-dev/2003-<u></u>February/052659.html</a> <br>
[2] <a href="http://lists.squeakfoundation.org/pipermail/squeak-dev/2009-November/141016.html" target="_blank">http://lists.squeakfoundation.<u></u>org/pipermail/squeak-dev/2009-<u></u>November/141016.html</a> <br>
<br>
<br>
<br>
On Wed, 26 Nov 2014, David T. Lewis wrote:<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
It seems to me that Object&gt;&gt;species is intended to handle this sort of issue.<br>
<br>
For IdentitySet, it answers what Eliot was expecting:<br>
<br>
  IdentitySet new species ==&gt; IdentitySet<br>
  Set new species ==&gt; Set<br>
<br>
However, IdentitySet&gt;&gt;collect: does not make use of this, and it answers<br>
a Set for the reasons that Levente explained.<br>
<br>
Answering an Array or and OrderedCollection would not really make sense,<br>
because sets are unordered collections (but Bag might be better).<br>
</blockquote></blockquote>
<br></span>
Bag is better.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Shouldn&#39;t we have an implementation of IdentitySet&gt;&gt;species that answers<br>
Set (or Bag), with a method comment explaining why this is the case, and<br>
with all of the collection methods using #species to answer the right<br>
kind of result?<br>
<br>
I note that IdentitySet&gt;&gt;collect: answers a Set, but IdentitySet&gt;select:<br>
sends #species and therefore answers an IdentitySet.<br>
<br>
So I think that if we want the #species of an IdentitySet to be a Set,<br>
then we should make it so, and give it a method comment to explain the<br>
rationale. And the #collect: and #select: methods should both answer a<br>
result of that #species.<br>
</blockquote></blockquote>
<br></span>
I think the species of #collect: and #select: are intrinsically different. #collect: is a transformation.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Dave<br>
<br>
<br>
On Thu, Nov 27, 2014 at 01:14:30AM +0100, Levente Uzonyi wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Your example hides the problem of ordering - what Tobias is asking about -<br>
so here&#39;s another:<br>
<br>
(IdentitySet withAll: #(1 1.0)) collect: [ :each | each class ]<br>
<br>
If IdentitySet &gt;&gt; #collect: were returning an Array, then what would be the<br>
answer?<br>
<br>
{ SmallInteger. Float } or { Float. SmallInteger } ?<br>
</blockquote></blockquote></blockquote>
<br></span>
--&gt;  a Bag(SmallInteger Float)<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
If you really want to have the resulting collection have the same size,<br>
but avoid the problem with ordering, then what you really need is a Bag.<br>
</blockquote></blockquote></blockquote>
<br></span>
To me that makes the most sense.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
On Thu, 27 Nov 2014, Frank Lesser wrote:<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi Tobias,<br>
agree, a problem of &quot;OrderedCollection&quot;<br>
not to break a lot of other things we could return an Array.<br>
but for me collecting has priority.<br>
Frank<br>
<br>
-----Urspr?ngliche Nachricht-----<br>
Von: <a href="mailto:squeak-dev-bounces@lists.squeakfoundation.org" target="_blank">squeak-dev-bounces@lists.<u></u>squeakfoundation.org</a><br>
[mailto:<a href="mailto:squeak-dev-bounces@lists.squeakfoundation.org" target="_blank">squeak-dev-bounces@<u></u>lists.squeakfoundation.org</a>] Im Auftrag von<br>
Tobias<br>
Pape<br>
Gesendet: Donnerstag, 27. November 2014 00:48<br>
An: The general-purpose Squeak developers list<br>
Betreff: Re: [squeak-dev] IdentitySet&gt;&gt;collect:<br>
<br>
<br>
On 27.11.2014, at 00:34, Frank Lesser &lt;<a href="mailto:frank-lesser@lesser-software.com" target="_blank">frank-lesser@lesser-software.<u></u>com</a>&gt;<br>
wrote:<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
hmm, not convinced<br>
<br>
(IdentitySet withAll: #(1 1.0)) collect: [:e| e asInteger ]<br>
OrderedCollection(1 1 )<br>
<br>
in LSWVST ( one-to-one ), you collect results of evaluating a block on<br>
objects.<br>
<br>
Frank<br>
maybe I am wrong ...<br>
</blockquote>
<br>
Where would the order come from for that _Ordered_Collection?<br>
</blockquote></blockquote></blockquote></blockquote>
<br></span>
An unordered OrderedCollection --&gt; Bag<br>
<br>
cheers -ben<br>
<br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature">best,<div>Eliot</div></div>
</div></div>