Am Mi., 1. Jan. 2020 um 21:55 Uhr schrieb Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Le mer. 1 janv. 2020 à 21:02, Jakob Reschke <forums.jakob@resfarm.de> a écrit :
Am Mi., 1. Jan. 2020 um 20:44 Uhr schrieb Nicolas Cellier <nicolas.cellier.aka.nice@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. 215).

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.