As Beck explains, some clients may need to enumerate a collection in a way that the elements are sorted before exposing them, others would require not iterating twice over the same object (which may appear twice in the collection), etc.
One way to address these situations would be to add methods such as #sortedDo:
, #withoutDuplicatesDo:
, etc. to the collection class. Sooner or later, this approach would derive in populating the class with other variants of #do:
such as #sortedSelect:
, #withoutDuplicatesCollect:
, and the like. The problem is that the resulting protocol of the class would quickly grow too large, adding complexity to the simple task of finding the right selector, increasing the risk of duplicating pieces of code when the search is not exhaustive enough, etc.
To avoid those side effects, the class should provide methods for converting its instances in instances of other classes. So, instead of #sortedDo:
the client may use
aCollection asSortedCollection do: aBlock
or
aCollection asSet do: aBlock
for iterating without duplicates.
This explains why we have abundant conversion methods: #asArray
, #asOrderedCollection
, etc. Note also that conversion methods are not restricted to collections, they are also available for other classes: #asInteger
, #asFloat
, #asString
, #asSymbol
, etc. Thanks to them, the services that clients usually need can be obtained by combining a conversion with the appropriate message, without overwhelming the class of the object at hand with all possible combinations, which would multiply (rather than add) all the possibilities.