<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jan 31, 2017, at 12:18 PM, Matthew Johnson &lt;<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><br class="Apple-interchange-newline">On Jan 31, 2017, at 1:16 PM, Ben Cohen via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">I think whether enumerated() is justified as a method on Sequence is one example of a wider question which definitely needs some discussion, which is: where should the standard library draw the line in providing convenience functions that can easily be composed from other functions in the std lib? Here’s another example:&nbsp;</div><div class=""><br class=""></div><div class=""><a href="https://github.com/apple/swift-evolution/blob/master/proposals/0100-add-sequence-based-init-and-merge-to-dictionary.md" class="">SE-100</a>&nbsp;is a proposal to add an init to Dictionary from a sequence of key/value pairs. It’s a commonly requested feature, and IMO much needed and should be added as soon as we move to the appropriate phase in Swift’s evolution.&nbsp;</div><div class=""><br class=""></div><div class="">Another commonly requested Dictionary feature is similar: add a Dictionary.init that takes a sequence, and a closure that maps that sequence to keys. This is useful, for example, when you have a sequence of objects that you frequently need to index into via one property on those objects, so you want to build a fast lookup cache using that property.</div><div class=""><br class=""></div><div class="">Now, if we implement SE-100, that second request can be easily composed. It would be something like Dictionary(sequence.lazy.map { (key: $0.someProperty, value: $0) } )</div><div class=""><br class=""></div><div class="">Some people look at that line of code and think sure, that’s what I’d do and it’s easy enough that the second helper shouldn’t be added as it’s superfluous. Others look at it and say that it is unreadable clever-code FP nonsense, and we should just add the helper method because most programmers wouldn’t be able to read or write that easily.</div><div class=""><br class=""></div><div class="">As we expand (and maybe contract :) the standard library, this kind of question comes up a lot, so it is worth setting out some criteria for judging these</div></div></div></blockquote><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">“helper” methods. Here’s my take on such a list (warning: objectivity and subjectivity blended together in the below).</div></div></div></blockquote><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">This is a great analysis and list of criteria. &nbsp;Thanks for putting this together Ben!</div><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class=""><b class="">1. Is it truly a frequent operation?</b></div><div class=""><br class=""></div><div class="">The operation needs to carry its weight. Even once we have ABI stability, so the size of the std lib becomes less of a concern as it could ship as part of the OS, we still need to keep helper method growth under control. APIs bristling with methods like an over-decorated Xmas tree are bad for usability. As mentioned in the String manifesto, String+Foundation currently has over 200 methods/properties. Helpers are no good if you can’t find them to use them.</div><div class=""><br class=""></div><div class="">Someone mentioned that they actually don’t find themselves using enumerated() all that often. I suspect enumerated in its current form isn’t all that useful. In a quick (and non-scientific) review of search results for its use on GitHub, nearly all the examples I see of it are either 1) misuse – see more below, or 2) use of it to perform the equivalent of in-place map where the index is used to subscript into the array and replace it with a transformed element.</div><div class=""><br class=""></div><div class="">I think the std lib needs an in-place map, and if enumerated() is removed, this one most-common use case should be added at the same time.</div></div></div></blockquote><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">I just did a quick search in a couple of projects and found a handful of good examples of valid uses of `enumerated`. &nbsp;I have simplified the examples from real world code, but I think they demonstrate the kinds of things this is good for.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">// only show the first 5 views</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">for&nbsp;(i, view)&nbsp;in&nbsp;views.enumerated() {</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">&nbsp; &nbsp; view.hidden = i &gt;= 5</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">}</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div></div></blockquote><div><br class=""></div><div>Interesting that several of these rely on reference types as elements. This does make the loops a lot simpler. In-place amendment of an array would be messier, and the combination with zip definitely pushes back against my notion that an in-place map would be a useful alternative (since you couldn’t mutate the mutable half of the&nbsp;<i class="">zipped</i>&nbsp;collection in-place without us jumping through some hoops).</div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">// apply alternating view background colors</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">for (i, view) in views.enumerated() {</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">&nbsp; &nbsp; view.backgroundColor = i % 2 ? bgColor1 : bgColor2</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">}</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div></div></blockquote><div><br class=""></div><div>This is an interesting one because it highlights something else I think is missing from the std lib: Sequence.cycle, which would make an infinite sequence by repeating a sequence, enabling what I think is probably a readability win in some cases:</div><div><br class=""></div><div>let colors = [bgColor1, bgColor2].cycle</div><div>for (color, view) in zip(colors, views) {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>view.backgroundColor = color</div><div>}</div><div><br class=""></div><div>Also i%2 used as a boolean – what language is this? :)</div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">// linear layout</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">for (i, view) in views.enumerated() {</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">&nbsp; &nbsp;let x = width * CGFloat(i)</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">&nbsp; &nbsp;view.frame = CGRect(x: x, y: 0, width: width, height: height)</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">}</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">// deriving locations for an equally spaced gradient</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">let locations = colors.enumerated.map { CGFloat($0.0) / CGFloat(colors.count - 1) }</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div></div></blockquote><div><br class=""></div><div>This one feels like it’s an example of enumerate discouraging use of stride, which hits cases 2: readability and 4: performance (unlike the others, where the alternatives are no better or worse)&nbsp;</div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">There are other ways to accomplish similar things (use `prefix` and `dropFirst` comes to mind), but many reasonable people would argue that using `enumerated` is a very straightforward way to do a lot of things.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div></div></blockquote><div><br class=""></div><div>Totally. Enumerating things is certainly sometimes useful, I just don’t think it’s useful enough to have a dedicated but inflexible method to do it.</div><br class=""><blockquote type="cite" class=""><div class=""><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class=""><b class="">2. Is the helper more&nbsp;readable? Is the composed equivalent obvious at a&nbsp;glance</b><b class="">?</b></div><div class=""><br class=""></div><div class="">When an operation is very common, the big win with a helper method is it creates a readable vocabulary. If enumerated() is very common, and everyone sees it everywhere, it makes that code easier to read at a glance.</div><div class=""><br class=""></div><div class="">That said, I think that the alternative – zip(0…, sequence) – is just as readable once you are familiar with zip and ranges, two concepts that, IMO at least, it is important that every Swift programmer learn about early on. I would even go so far as to say that enumerated is harmful if it discourages new users from discovering zip.</div></div></div></blockquote><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">This is a very good point. &nbsp;Requiring programmers to zip with a range could help them to learn to think a little bit differently and learn more general tools. &nbsp;That’s a good thing. &nbsp;</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">The other thing it does is make the order of the index and the value more clear at the call site. &nbsp;I think this is a very important point. &nbsp;I always forget which order `enumerated` uses every time I reach to use it.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Of course the current alternative is actually `zip(0..&lt;sequence.count, sequence)` which is not so great. &nbsp;</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div></div></blockquote><div><br class=""></div><div>Totally. zip replacing enumerated will only fly in combination with one-sided ranges.</div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">In order to make `zip(0…, sequence)` a workable alternative we would need to grab `…` as a unary postfix operator which produces a sequence by incrementing values. &nbsp;Is that something we want to do? &nbsp;If the answer turns out to be yes, then I am in agreement with your analysis. &nbsp;The composed alternative would be superior and `enumerated` wouldn’t carry it’s weight.</div><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"></div></blockquote><div><br class=""></div><div>I think based on the String discussions there’s fairly well-established support for one-sided &nbsp;…</div><div><br class=""></div><blockquote type="cite" class=""><div class=""><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class="">OTOH, an example that I think is strongly justified on readability grounds is Sequence.all(match:), a function that checks that every element in a sequence matches a predicate. This is by far the most common extension for Sequence on GitHub. Yes, you can write this as !seq.contains(!predicate) but that far less readable – especially since it requires you write it with a closure that !’s the predicate i.e. !seq.contains { !predicate($0) }, because we don’t have a ! for composing with predicate functions (though maybe we should).</div><div class=""><br class=""></div><div class=""><b class="">3. Does the helper have the flexibility to cover all common cases?</b></div><div class=""><br class=""></div><div class="">This, I think, is where enumerated() really starts to fall down.</div><div class=""><br class=""></div><div class="">Sometimes you want to start from not-zero, so maybe it should be Sequence.enumerated(startingFrom: Int = 0)</div><div class="">Sometimes you want non-integer indices so maybe we should add indexed().</div><div class="">Sometimes you want it the other way around (not for a for loop but for passing the elements directly into a mapping function) so now you need a flip.</div><div class="">Sometimes you want to enumeration to run backwards in some way.</div><div class=""><br class=""></div><div class="">Less of a problem if you’re already accustomed to composing your enumeration:</div><div class=""><br class=""></div><div class="">Enumerate starting from 1: zip(1…, c)</div><div class="">Enumerate indices: zip(c.indices, c)</div><div class="">Need the pair to be the other way around: zip(c, 0…)</div><div class="">Need the enumeration to run the other way: zip((0..&lt;c.count).reversed,c) or zip(0…,c).reversed() or zip(0…,c.reversed()).</div><div class=""><br class=""></div><div class="">Similarly, for the Dictionary helper – what if you want a sequence, and a closure to map keys to values, rather than values to keys?</div><div class=""><br class=""></div><div class=""><div class="">(zip also needs to retain its collection-ness, which is filed as SR-3760, a great starter proposal if anyone wants to take it on :)</div></div><div class=""><br class=""></div><div class=""><b class="">4. Is there a correctness trap with the composed equivalent? Is there a correctness trap with the helper?</b></div><div class=""><br class=""></div><div class="">As others noted on the thread, enumerated() used for indices encourages a possible correctness error:</div><div class=""><br class=""></div><div class="">for (idx, element) = someSlice.enumerated() { } // slices aren’t zero based!</div><div class=""><br class=""></div><div class="">Now, chances are that since out-of-bounds subscripting traps on arrays, this bug would be caught early on. But maybe not – especially if you ended up using it on an UnsafeBufferPointer slice (perhaps dropped in for performance reasons to replace an Array) and now all of a sudden you have a memory access violation that could go undetected.</div><div class=""><br class=""></div><div class="">On the flip side: many operations on collections that use indices are hard to get right, especially ones that involve mutating as you go, like removing elements from a collection based on some criteria, where you have to work around index invalidation or fencepost errors. For this reason, the std lib probably ought to have a RangeReplaceableCollection.remove(where:) method so people don’t have to reinvent it and risk getting it wrong.</div><div class=""><br class=""></div><div class=""><b class="">5. Is there a performance trap with the composed equivalent? Or with the helper?</b></div><div class=""><br class=""></div><div class="">The composed example of Dictionary from a sequence+closure, you need to remember the .lazy part in sequence.lazy.map to avoid creating a temporary array for no reason. A helper method might lift that burden from the user. remove(where:) can easily be accidentally quadtratic, or perform needless element copies when there’s little or nothing to remove.</div><div class=""><br class=""></div><div class="">Counter example: the fact that map is eager and chaining it creates temporary arrays needlessly is a performance problem caused by introducing it as a helper method.</div><div class=""><br class=""></div><div class=""><b class="">6. Does the helper actually encourage misuse?</b></div><div class=""><br class=""></div><div class=""><div class="">This is a very common pattern when searching GitHub for uses of enumerated():&nbsp;</div><div class=""><br class=""></div><div class="">for (index, _) in collection.enumerated() {&nbsp;</div><div class="">&nbsp; &nbsp; mutate collect[index] in-place i.e. collection[index] += 1</div><div class="">}.</div><div class=""><br class=""></div><div class="">(or even they assign the element then don’t use it, for which specific case we don’t currently emit a warning)</div><div class=""><br class=""></div><div class="">What the user really needs is just:</div><div class=""><br class=""></div><div class="">for index in collection.indices { etc. }</div></div><div class=""><br class=""></div><div class="">I expect if the standard way to do enumerated was with zip, people wouldn’t do this as often. In-place map would be even better.</div><div class=""><br class=""></div><div class=""><b class="">8. Can a native implementation be made more performant than the equivalent composition?</b></div><div class=""><br class=""></div><div class="">Dictionary.mapValues(transform: (Value)-&gt;T) can be implemented internally much more efficiently than just composing it with map and the key/value sequence initializer, because the layout of the hash table storage can be re-used in the new dictionary, even when the Value type is different.</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Jan 31, 2017, at 6:24 AM, Chris Eidhof via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">Hey everyone,<div class=""><br class=""></div><div class="">I've organized a number of Swift workshops over the last two years. There are a couple of things that keep coming up, and a couple of mistakes that I see people making over and over again. One of them is that in almost every workshop, there's someone who thinks that `enumerated()` returns a list of (index, element) pairs. This is only true for arrays. It breaks when using array slices, or any other kind of collection. In our workshops, I sometimes see people doing something like `x.reversed().enumerated()`, where `x` is an array, and somehow it produces behavior they don't understand.</div><div class=""><br class=""></div><div class="">A few ways I think this could be improved:</div><div class=""><br class=""></div><div class="">- Move enumerated to Array</div><div class="">- Change enumerated to return `(Index, Iterator.Element)` (this would mean we at least need to move it to collection)</div><div class="">- Remove enumerated</div><div class="">- Keep things as is</div><div class=""><br class=""></div><div class="">In any case, just wanted to share my experience (gained from teaching people).&nbsp;</div><div class=""><div class=""><br class=""></div>--<span class="Apple-converted-space">&nbsp;</span><br class=""><div class="gmail_signature" data-smartmail="gmail_signature">Chris Eidhof</div></div></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br class=""></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div></blockquote></div><br class=""></body></html>