[squeak-dev] The Inbox: Collections-nice.869.mcz

Jakob Reschke forums.jakob at resfarm.de
Wed Jan 1 22:11:11 UTC 2020

Am Mi., 1. Jan. 2020 um 21:55 Uhr schrieb Nicolas Cellier <
nicolas.cellier.aka.nice at gmail.com>:

> Le mer. 1 janv. 2020 à 21:02, Jakob Reschke <forums.jakob at resfarm.de> a
> écrit :
>> Am Mi., 1. Jan. 2020 um 20:44 Uhr schrieb Nicolas Cellier <
>> nicolas.cellier.aka.nice at gmail.com>:
>>> Introducing a different selector would mean implementing it in other
>>> collection too.
>> Not necessarily. Set also does not understand #before:, you must use a
>> SequenceableCollection if you want it. Conversely if you knowingly use a
>> RunArray (as in Text) and you want to exploit the optimization for the
>> iteration blocks, you could use the new selector(s).
>> In my case, the client class had no idea whether a RunArray would be used
> as storage or not.
> So that would mean either a beautiful isSomething query, or a common
> selector for all the possible storage class.

Ok but then you would still get away with

Collection>>collectWithoutSideEffects: aBlock
    "Transform my elements using aBlock, which is only guaranteed to be
evaluated at least once per distinct element."
    ^ self collect: aBlock "implementation detail"

and specializing that for RunArray.

It's like we want to do: and collect: in the same loop.
> The proper way to write the example given by Christoph would be something
> like:
>     (1 to: runArray size) with: runArray collect: [:i :v | i].

Or rather just (1 to: runArray size), but that is beside the point.
The question is whether we have such an answer for all uses of
collect:-with-side-effects. It is hard to answer unless we can enumerate
all possible uses of collect:-with-side-effects. :-)

> For example, if you do that with an Unordered collection, you'll get a
> different result too with #collect:as: and (#collect:)#as: too.
> That's not unexpected. Enumeration order is implementation defined anyway.

Yes, but in addition to that difference, in Christoph's example, the
intermediary RunArray (before #as) is also wrong (or unexpected) in my
opinion, not just the end result.

> IMO, the fact that current phrasing explicitely tells about iterating on
> each elements does not have to be taken too literally.
> It means that the block argument is applied on a single element at a time.
> Try writing the comment without that contract in mind:
>     "Answer a collection like the receiver whose elements are transformed
> using aBlock"
Would that still include that the result collection is still of the same
size as the receiver collection? This I consider important. And it somehow
implies to me that the elements are transformed one by one because the
block also only gets one element for each invocation.

> IMO, it was not the spirit of the original contract :)

For what it's worth, the Blue Book states: "Evaluate the argument, aBlock,
for each of the receiver's elements. Answer a new collection like that of
the receiver containing the values returned by the block on each
evaluation." (p. 137).
The subsequent example, contrary to the one provided by Christoph, makes
use of the block argument, of course: "The resulting collection is the same
size as [the original collection]. Each of the elements of the new
collection is the [collected property] of the corresponding elements of
[the original collection]." (p. 138).

The ANSI draft v1.9 states: "Answer a new collection constructed by
gathering the results of evaluating [the block] with each element of the
receiver. [...] For each element of the receiver, [the block] is evaluated
with the element as the parameter." (p. 160) The refinements for subtypes
are about Dictionary keys (p. 168), nil in hashed collections (pp. 178,
180), removed duplicates in Set (p. 180), and returning a different
collection type in the cases of Interval (p. 194) and SortedCollection (p.

So I think the new RunArray implementation deviates at least from the
standard draft or would introduce a weighty refinement.

> IMO we have to unlearn some of our biased expectations (and of course this
> includes myself), we have been abusing those side effects for too long.

Maybe, and it sure is purer without side-effects. But in the end Smalltalk
blocks explicitly support side-effects. So I am wary to forbid them in an
operation as general as #collect:. Although "forbid" is the wrong word,
since one can still use side-effects, only not rely on them to behave
equally under all circumstances.

I would favor the least surprising behavior rather than the most efficient
if they contradict each other.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20200101/6d9c6712/attachment.html>

More information about the Squeak-dev mailing list