[ANSI-Smalltalk] Behaviour of #collect:
Andrew Wakeling
andrew.wakeling at objective.com
Fri Oct 10 05:20:38 BST 2008
I deeply apologise for sharing my opinion.
I will surely remember this response before do so in future.
-----Original Message-----
From: ansi-smalltalk-bounces at lists.openskills.org
[mailto:ansi-smalltalk-bounces at lists.openskills.org] On Behalf Of
Richard O'Keefe
Sent: Friday, 10 October 2008 10:14 AM
To: Discussion list for the ANSI Smalltalk project
Subject: Re: [ANSI-Smalltalk] Behaviour of #collect:
On 9 Oct 2008, at 6:52 pm, Andrew Wakeling wrote:
> Sorry for my belated response to this thread.
>
> We have solved a similar pattern/problem in such a way:
>
> aCollection collectAsSet: [:item | item foo]
The problem with this is that you end up with a vast number
of collectAsXXX methods.
Let's take just the ones I'd need for my collection library:
collectAsReadOnlyArray:
collectAsArray:
collectAsVectorI:
collectAsVectorE:
collectAsVectorD:
collectAsVectorQ:
collectAsReadOnlyBooleanArray:
collectAsBooleanArray:
collectAsReadOnlyByteArray:
collectAsByteArray:
collectAsReadOnlyString:
collectAsString:
collectAsSymbol:
collectAsRunArray:
collectAsSortedCollection:[sortBlock:]
collectAsOrderedCollection:
collectAsSortedDictionary:[sortBlock:]
collectAsSortedSet:[sortBlock:]
collectAsSortedBag:[sortBlock:]
collectAsDictionary:
collectAsIdentityDictionary:
collectAsPluggableDictionary:equalBlock:hashBlock:
collectAsSet:
collectAsIdentitySet:
collectAsPluggableSet:equalBlock:hashBlock:
collectAsBag:
collectAsIdentityBag:
collectAsPluggableBag:equalBlock:hashBlock:
collectAsDeque:
collectAsHeap:[sortBlock:]
and I've actually left out some.
The horrible thing about this is that when you add a new collection
type (Deap, say) you have to rush around adding collectAsDeap: in
various places, and are never quite sure you've covered all of them.
Contrast this with
withAll:collect:
sortBlock:withAll:collect: (Sorted collections)
equalBlock:hashBlock:withAll:collect: (Pluggable collections)
where
(1) there are only three messages to remember,
(2) when you add a new collection type (Deap, say), you just
implement the appropriate methods (in this case,
[sortBlock:]withAll:collect:) in that class as part of
the normal process of implementing that class.
In sort, #collectAsSet: is not at all the kind of thing you would
end up with by following the GRASP patterns. Neither are the
traditional #asXXX methods, and having to rush around implementing
#asXXX methods all over the place taught me that their omission from
the ANSI Smalltalk standard was a really excellent decision.
Note also that if you use
someClass withAll: aCollection collect: aBlock
then the class can be a parameter. If you use
aCollection collectAsSomeClass: aBlock
then the class cannot be a parameter.
> This could be assisted with helper method such as:
>
> Collection>>collectAsSpecies: aSpecies from: aBlock
"from:" doesn't really make sense here.
The "species" concept is really too ambiguous to rely on.
>
> (or even Collection>>collectAsSpecies: aSpecies using: aBlock)
>
> We did a similar "optimization" with Dictionary>>value (as it is
> implemented to always return a Bag, which was expensive as it was
> doing
> unwanted equality checks). (e.g.
> Dictionary>>valuesAsOrderedCollection)
There is no Dictionary>>value in the ANSI standard, in VisualWorks,
or Squeak. I presume this was a typo for #values, especially
since the next method name has the "s" in it.
Section 5.7.2.19 specifies that the result of #values should be
a <sequencedReadableCollection>, which Bag is not. Of the
Smalltalks I checked, one returned an Array, one an OrderedCollection,
and one returns a ReadOnlyArray. It is definitely wrong for
Dictionary>>values to return a Bag. Ever.
The idea of having a couple of dozen #valuesAsXXXX methods
(and another couple of dozen #keysAsXXXX methods) does not
appeal to me. It's so simple to
(1) have Dictionary>>values return a sequence
(the entire implementation of #values in my library is
values
^ReadOnlyArray withAll: self
)
(2) use the ANSI Smalltalk #withAll: methods at other times, e.g.,
Bag withAll: aDictionary "collects the values"
>
> Sure, for my above example (with Sets), the same thing could be
> achieved
> doing:
> aCollection asSet: [:item | item foo]
>
> however for large collections there will probably be a consideration
> performance difference, especially if you items you're checking have
> an
> expensive equality method.
Using
someCollectionClass withAll: aCollection "existing"
someCollectionClass withAll: aColllection collect: aBlock "new"
is efficient.
>
> Using a class method (or constructor) is fine too, however the above
> approach is easier to access through our AutoComplete IDE tool.
It had never previously occurred to me that autocompletion
could encourage poor factoring. I am greatly indebted to you
for this example. It's a pity I gave my last software engineering
lecture of the year this morning, otherwise I would certainly have
used this as a Dreadful Warning.
_______________________________________________
ANSI-Smalltalk mailing list
ANSI-Smalltalk at lists.openskills.org
http://lists.openskills.org/cgi-bin/mailman/listinfo/ansi-smalltalk
More information about the ANSI-Smalltalk
mailing list