[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