<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Le mer. 1 janv. 2020 à 23:11, Jakob Reschke <<a href="mailto:forums.jakob@resfarm.de" target="_blank">forums.jakob@resfarm.de</a>> a écrit :<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr">Am Mi., 1. Jan. 2020 um 21:55 Uhr schrieb Nicolas Cellier <<a href="mailto:nicolas.cellier.aka.nice@gmail.com" target="_blank">nicolas.cellier.aka.nice@gmail.com</a>>:</div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Le mer. 1 janv. 2020 à 21:02, Jakob Reschke <<a href="mailto:forums.jakob@resfarm.de" target="_blank">forums.jakob@resfarm.de</a>> a écrit :<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr">Am Mi., 1. Jan. 2020 um 20:44 Uhr schrieb Nicolas Cellier <<a href="mailto:nicolas.cellier.aka.nice@gmail.com" target="_blank">nicolas.cellier.aka.nice@gmail.com</a>>:</div><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>Introducing a different selector would mean implementing it in other collection too.</div></div></div></blockquote><div><br></div><div>

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).</div></div></div>
<br></blockquote><div>In my case, the client class had no idea whether a RunArray would be used as storage or not.</div>So that would mean either a beautiful isSomething query, or a common selector for all the possible storage class.</div></div></blockquote><div><br></div><div>Ok but then you would still get away with</div><div><br></div><div>Collection>>collectWithoutSideEffects: aBlock</div><div>    "Transform my elements using aBlock, which is only guaranteed to be evaluated at least once per distinct element."</div><div>    ^ self collect: aBlock "implementation detail"</div><div><br></div><div>and specializing that for RunArray.</div><div><br></div></div></div></blockquote><div><br></div><div>On the contrary, I would implement collectEachAndEvery: if someone depending on side effects really insist on legacy behavior.</div><div>RunArray is unused (Text handling does not depend on such side effect) and new definition is not going to cause any compatibility problem.<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote">It's like we want to do: and collect: in the same loop.<br></div><div class="gmail_quote">The proper way to write the example given by Christoph would be something like:</div><div class="gmail_quote"><br></div><div class="gmail_quote">    (1 to: runArray size) with: runArray collect: [:i :v | i].</div></div></blockquote><div><br></div><div>Or rather just (1 to: runArray size), but that is beside the point.</div><div>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. :-)</div><div> </div></div></div></blockquote><div>Well, we can detect block closing over outer variables and writing into them, but that's a restrictive notion of side effects.</div><div>But YAGNI, RunArray usage is very limited as said above.<br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote">For example, if you do that with an Unordered collection, you'll get a different result too with #collect:as: and (#collect:)#as: too.<br></div><div class="gmail_quote">That's not unexpected. Enumeration order is implementation defined anyway.<br></div></div></blockquote><div><br></div><div>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.</div><div> </div></div></div></blockquote><div>Yes.</div><div>Because we are thinking implementation-wise, like the comment has taught us to do.<br></div><div>That is what must be unlearnt.</div><div><br> </div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"></div><div class="gmail_quote">IMO, the fact that current phrasing explicitely tells about iterating on each elements does not have to be taken too literally.<br></div><div class="gmail_quote"><div>It means that the block argument is applied on a single element at a time.</div></div><div class="gmail_quote"><br></div><div class="gmail_quote">Try writing the comment without that contract in mind:</div><div class="gmail_quote"><div>    "Answer a collection like the receiver whose elements are transformed using aBlock"</div><div><br></div></div></div></blockquote><div><br></div><div>

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.</div><div></div></div></div></blockquote><div><br></div><div><div>Set collect: does not preserve size.</div>RunArray collect: does, new definition included.</div><div>The fact that it can collect a whole run at a time is just an implementation detail.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote">IMO, it was not the spirit of the original contract :)</div></div></blockquote><div><br></div><div>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).</div><div>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).</div><div><br></div><div>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).</div><div> <br></div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div></div><div>So I think 

the new RunArray implementation deviates 

at least from the standard draft or would introduce a weighty refinement.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote">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.<br></div></div></blockquote><div><br></div><div>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.</div><div><br></div></div></div></blockquote><div>We don't forbid side effects.</div><div>Just warn that using side effects on implementation defined enumeration will result in implementation defined behavior.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div></div><div>I would favor the least surprising behavior rather than the most efficient if they contradict each other.</div></div></div>
<br></blockquote><div>I understand.</div><div>But RunArray is all about optimization. It is its very logic to evaluate blocks once per run.<br></div><div>If we strictly adhere to this interpretation of method comment, detectMin: detectMax: detect:ifNone: and count: should also iterate on each and every element.</div><div>Do you agree that count: hardly benefits from such definition?<br></div></div></div>