<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 Jul 1, 2016, at 6:32 PM, Dave Abrahams &lt;<a href="mailto:dabrahams@apple.com" class="">dabrahams@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">on Fri Jul 01 2016, Matthew Johnson &lt;</span><a href="http://matthew-at-anandabits.com/" 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-stroke-width: 0px;" class="">matthew-AT-anandabits.com</a><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">&gt; wrote:</span><br 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-stroke-width: 0px;" class=""><br 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-stroke-width: 0px;" class=""><blockquote type="cite" 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-stroke-width: 0px;" class=""><blockquote type="cite" class="">On Jul 1, 2016, at 11:51 AM, Dave Abrahams &lt;<a href="mailto:dabrahams@apple.com" class="">dabrahams@apple.com</a>&gt; wrote:<br class=""><br class=""><br class="">on Fri Jul 01 2016, Matthew Johnson &lt;<a href="http://matthew-at-anandabits.com/" class="">matthew-AT-anandabits.com</a><span class="Apple-converted-space">&nbsp;</span>&lt;<a href="http://matthew-at-anandabits.com/" class="">http://matthew-at-anandabits.com/</a>&gt;&gt; wrote:<br class=""><br class=""></blockquote><br class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class="">On Jun 30, 2016, at 12:26 PM, Dave Abrahams &lt;<a href="mailto:dabrahams@apple.com" class="">dabrahams@apple.com</a>&gt;<br class=""></blockquote>wrote:<br class=""><blockquote type="cite" class=""><br class=""><br class="">on Wed Jun 29 2016, Haravikk &lt;<a href="http://swift-evolution-at-haravikk.me/" class="">swift-evolution-AT-haravikk.me</a>&gt; wrote:<br class=""><br class=""></blockquote><br class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class="">On 29 Jun 2016, at 00:10, Matthew Johnson via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:<br class=""><br class="">Swift is a language that embraces value semantics. &nbsp;Many common<br class="">iterators *can* be implemented with value semantics. &nbsp;Just because we<br class="">can’t implement *all* iterators with value semantics doesn’t mean we<br class="">should require them to have reference semantics. &nbsp;It just means you<br class="">can’t *assume* value semantics when working with iterators in generic<br class="">code unless / until we have a way to specify a value semantics<br class="">constraint. &nbsp;That’s not necessarily a bad thing especially when it<br class="">leaves the door open to interesting future possibilities.<br class=""><br class="">-Matthew<br class=""></blockquote><br class="">I'm kind of undecided about this personally. I think one of the<br class="">problems with Swift is that the only indication that you have a<br class="">reference type is that you can declare it as a constant, yet still<br class="">call mutating methods upon it, this isn't a very positive way of<br class="">identifying it however. This may be more of a GUI/IDE issue though, in<br class="">that something being a class isn't always that obvious at a glance.<br class=""><br class="">I wonder, could we somehow force iterators stored in variables to be<br class="">passed via inout? This would make it pretty clear that you're using<br class="">the same iterator and not a copy in all cases, encouraging you to<br class="">obtain another if you really do need to perform multiple passes.<br class=""></blockquote><br class="">I'm going to push single-pass iteration on the stack briefly and talk<br class="">about the topic that's been under discussion here: infinite multipass<br class="">sequences.<br class=""><br class="">## Fitting “Infinite Multipass” Into the Model<br class=""><br class="">It remains to be decided whether it's worth doing, but if it's to<br class="">happen<br class=""></blockquote><br class="">I definitely think it’s worth doing. &nbsp;<br class=""></blockquote><br class="">Opinions are nice, but rationales are better. &nbsp;How will we understand<br class="">*why* it's worth doing?<br class=""></blockquote><br class="">I agree. &nbsp;<br class=""><br class="">The rationale has been discussed quite a bit already in this thread.<br class="">The current protocols do not provide the semantics many people are<br class="">assuming in their code, leading to a lot of code that is incorrect<br class="">despite the fact that it usually works in practice.<br class=""><br class="">This is especially frequent in the case of the finite assumption.<br class="">This assumption is so common it seems very wise to me to encode it as<br class="">a semantic requirement in a protocol.<br class=""><br class="">IMO these are problem worth addressing, especially now that we have a<br class="">good handle on what a solution would look like.<br class=""><br class=""><blockquote type="cite" class=""><br class=""><blockquote type="cite" class="">I really appreciate the attention that the library team has given to<br class="">this.<br class=""><br class=""><blockquote type="cite" class="">, the standard library team thinks the right design is roughly<br class="">this:<br class=""><br class="">/// A multipass sequence that may be infinite<br class="">protocol Collection {<br class=""><br class="">&nbsp;// Only eager algorithms that can terminate available here<br class="">&nbsp;func index(where predicate: (Element)-&gt;Bool) -&gt; Index<br class=""><br class="">&nbsp;// all lazy algorithms available here<br class="">&nbsp;var lazy: ...<br class=""><br class="">&nbsp;var startIndex: Index<br class="">&nbsp;var endIndex: Index // possibly not reachable from startIndex<br class=""><br class="">&nbsp;associatedtype SubSequence : Collection<br class="">&nbsp;// do we need an associated FiniteSubsequence, e.g. for prefixes?<br class="">}<br class=""><br class="">protocol FiniteCollection : Collection {<br class=""><br class="">&nbsp;// All eager algorithms available here<br class="">&nbsp;func map(...) -&gt;<br class="">&nbsp;var count: ...<br class="">}<br class=""><br class="">protocol BidirectionalCollection : Collection { ... }<br class=""><br class="">protocol RandomAccessCollection : BidirectionalCollection { … }<br class=""></blockquote><br class="">Does this design entirely break with the relationship between<br class="">collections and iterators (dropping `makeIterator` as a protocol<br class="">requirement)? &nbsp;If so, would for..in (over collections) be built on top<br class="">of indices and use `formIndex(after:)`? &nbsp;Would it require a finite<br class="">collection (unless we add `until` to the language and then allow<br class="">`for..in..until` to work with infinite collections)?<br class=""></blockquote><br class="">All of these points are up for discussion. &nbsp;<br class=""></blockquote><br class="">Cool. &nbsp;I think the collection for..in has some nice advantages, but<br class="">since it sounds like we’ll probably keep Iterator around it might be<br class="">best to take the approach of making them both work.<br class=""><br class="">You already know that I would prefer to see the current for..in built<br class="">on finite sequences and allow for..in..unitl to be used with infinite<br class="">sequences if we add that in the future. &nbsp;:)<br class=""><br class=""><blockquote type="cite" class="">John McCall pointed out to<br class="">me that an index-based for..in would make it possible to implement<br class=""><br class="">for inout x in y { mutate(&amp;x) }<br class=""></blockquote><br class="">That would be very nice!<br class=""><br class="">I think it might also increase performance. &nbsp;I don’t know exactly how<br class="">for..in is implemented today, but the implementation of<br class="">IndexingIterator compares position to endIndex. &nbsp;If for..in is also<br class="">comparing checking the optional for nil that’s an extra comparison.<br class="">We shouldn't need to actually construct the optional in the first<br class="">place using an index-based for..in. &nbsp;Maybe optimizations like this<br class="">already exist? &nbsp;But even if they do, it seems like they wouldn’t be<br class="">possible in some cases where the type of the sequence isn’t statically<br class="">known.<br class=""><br class=""><blockquote type="cite" class=""><br class=""><blockquote type="cite" class="">Would we still retain `IndexingIterator`even if we break the<br class="">relationship in the protocol requirements?<br class=""></blockquote><br class="">Yes: it should be possible to implement Collection algorithms in terms<br class="">of Iterator algorithms, and IndexingIterator provides the means. &nbsp;That<br class="">said, I think the makeIterator requirement does little harm, especially<br class="">when it can be defaulted for Collections.<br class=""></blockquote><br class="">I like this answer.<br class=""><br class=""><blockquote type="cite" class=""><br class=""><blockquote type="cite" class="">Would it still be possible to do things like zip a multi-pass sequence<br class="">with a single-pass sequence (assuming we keep single-pass sequences or<br class="">add them back eventually)? &nbsp;This seems like a use case worth<br class="">supporting in some way.<br class=""></blockquote><br class="">Yes. &nbsp;If you can create an Iterator from a Collection, and you can zip<br class="">Iterators, you can do this.<br class=""></blockquote><br class="">Yes, of course. &nbsp;I’m glad we would keep this relationship in tact.<br class=""><br class=""><blockquote type="cite" class=""><br class=""><blockquote type="cite" class="">One subtle change I think this implies is that things like<br class="">`LazyFilterSequence` can implement `makeIterator` with constant<br class="">complexity, deferring the O(N) complexity to the first call to `next`.<br class=""></blockquote><br class="">I don't believe that's a difference, though I could be wrong.<br class=""></blockquote><br class="">You’re right, I was wrong. &nbsp;`LazyFilterSequence` just constructs an<br class="">iterator and returns it. &nbsp;`LazyFilterCollection` has to loop until it<br class="">finds the first item matching the predicate in its `startIndex`<br class="">implementation. &nbsp;The part I was missing is that `IndexingIterator`<br class="">gets the `startIndex` in its initializer.<br class=""><br class=""><blockquote type="cite" class=""><br class=""><blockquote type="cite" class="">`startIndex` for `LazyFilterCollection` currently has O(N) complexity.<br class="">The complexity of a complete iteration doesn’t change and probably<br class="">isn’t a big deal, but it’s worth noting.<br class=""></blockquote><br class="">Filtered collection views always require a bit of hand-waving around<br class="">performance guarantees; I don't think that changes.<br class=""><br class=""><blockquote type="cite" class="">I’ve been looking at some code that wraps a sequence and considering<br class="">how it would be impacted. &nbsp;With iterators it looks like this:<br class=""><br class="">guard let element = base.next()<br class="">else { return nil }<br class=""><br class="">With collections and indices it would look something like this:<br class=""><br class="">base.formIndex(after: &amp;index)<br class="">guard index != baseEndIndex<br class="">&nbsp;else { return endIndex }<br class=""><br class="">let element = base[index]<br class=""><br class="">That’s not too bad but it is more verbose. &nbsp;<br class=""></blockquote><br class="">Sequence today is a single-pass thing. &nbsp;If you are wrapping Sequence<br class="">today presumably you'd wrap an Iterator tomorrow, and you wouldn't have<br class="">to deal with indices.<br class=""><br class=""><blockquote type="cite" class="">If we’re going to push people towards collections and indices we<br class="">should try to make common patterns like “update the iteration state<br class="">and return the next element if there is one" simpler. &nbsp;<br class=""></blockquote><br class="">That's IndexingIterator.<br class=""></blockquote><br class="">Cool, I wrote this thinking that was going away.<br class=""><br class=""><blockquote type="cite" class=""><br class=""><blockquote type="cite" class="">This could be accomplished with an extension method along these lines:<br class=""><br class="">guard let element = base.formIndex(after: &amp;index,<br class="">.returningOptionalElement)<br class="">&nbsp;&nbsp;else { return endIndex }<br class=""><br class="">With an implementation something like:<br class=""><br class="">enum FormIndexResult {<br class="">&nbsp;&nbsp;.returningOptionalElement<br class="">}<br class="">extension Collection {<br class="">&nbsp;&nbsp;func formIndex(after i: inout Self.Index, _ result:<br class="">FormIndexResult) -&gt; Self.Element?<br class="">}<br class=""><br class="">This would provide similar functionality to `IndexingIterator` without<br class="">coupling the storage of `elements` and `position` (which is important<br class="">if you’re wrapping a collection and need to wrap the collection and<br class="">its indices independently).<br class=""></blockquote><br class="">I'm afraid I don't understand. &nbsp;Could you be more explicit about what<br class="">you have in mind?<br class=""></blockquote><br class="">The idea was to provide functionality similar to `IndexingIterator` in<br class="">the sense the following code would provide equivalent functionality to<br class="">`iterator.next()` but expressed in terms of a collection and an index:<br class=""><br class="">let optionalElement = myCollection.formIndex(after: &amp;myIndex, . returningOptionalElement)<br class=""><br class="">vs<br class=""><br class="">let optionalElement = myIterator.next()<br class=""><br class="">The single case enum is just there to provide a label that<br class="">differentiates the overload.<br class=""><br class="">If we’re keeping IndexingIterator this probably isn’t necessary. &nbsp;I<br class="">still have a use case for it but it is rather obscure.<br class=""></blockquote><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">I can imagine wanting a design like the above for cases where</span><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">implementing the endIndex requires adding an extra bit of state, e.g. in</span><br 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-stroke-width: 0px;" class=""><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">&nbsp;struct LazyPrefix&lt;Base: Collection&gt; : Collection {</span><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">&nbsp;&nbsp;&nbsp;init(_ base: Base, where: (C.Element)-&gt;Bool)</span><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">&nbsp;&nbsp;&nbsp;...</span><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">&nbsp;}</span><br 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-stroke-width: 0px;" class=""><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">you don't want to traverse the base collection eagerly just to come up</span><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">with an endIndex, so you store an optional Base.Index in</span><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">LazyPrefix.Index, which is nil for the endIndex. &nbsp;In these cases, index</span><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">comparison is less efficient than it might otherwise be.</span><br 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-stroke-width: 0px;" class=""><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">But my answer for these cases is simple: simply use a specialized</span><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">Iterator that will be more efficient than IndexingIterator. &nbsp;Is there a</span><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">reason that doesn't work for your case?</span><br 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-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>I would index a custom iterator in my case, but I am talking about code that would live inside the implementation of `index(after:)` in the `Collection` conformance of a wrapper `Collection` that bears some resemblance to `LazyFlattenCollection`. &nbsp;In this case you are receiving your `Index` which wraps `Base.Index`.</div><div><br class=""></div><div>Like I said, this is a pretty obscure case and I would never suggest including it on the grounds of a use case that is only relevant to `index(after:)` implementations in wrapper collections. :) &nbsp;I brought it because I thought you may have been suggesting a more drastic change that removed the collection iterators.</div><br class=""><blockquote type="cite" class=""><div class=""><br 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-stroke-width: 0px;" class=""><blockquote type="cite" 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-stroke-width: 0px;" class=""><blockquote type="cite" class="">On second thought, I believe it is important to have a way to support<br class="">existing “partially formed” multipass sequences that don't expose<br class="">copying or equality for their iteration states. &nbsp;<br class=""></blockquote><br class="">Can you provide examples of these? &nbsp;I’m having difficulty thinking of<br class="">one.<br class=""></blockquote><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">NSSet is an example.</span><br 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-stroke-width: 0px;" class=""><br 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-stroke-width: 0px;" class=""><blockquote type="cite" 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-stroke-width: 0px;" class=""><blockquote type="cite" class="">Iterator is the right way to do that. &nbsp;So I think we need to keep<br class="">Iterator around.<br class=""></blockquote><br class="">I don’t have any objection to keeping it either. :) Hopefully we’d<br class="">still be able to improve the design in the future if / when new<br class="">enabling language features come along.<br class=""><br class=""><blockquote type="cite" class=""><br class=""><blockquote type="cite" class="">In the meantime, people would be able to implement their own protocol<br class="">for single pass sequences. &nbsp;What they would lose is for..in as well as<br class="">the standard library algorithms. &nbsp;I’m not sure how many people this<br class="">would impact or how big the impact would be for them. &nbsp;We have seen a<br class="">couple of examples in this discussion, but probably not enough to<br class="">asses the overall impact.<br class=""><br class="">One thing you don’t mention here is a distinction between finite and<br class="">infinite single-pass sequences (iterators). &nbsp;I don’t know if the<br class="">finite / infinite distinction is as important here, but wanted to<br class="">point it out. &nbsp;Obviously if we remove support single-pass sequences<br class="">now we could defer that discussion until we’re ready to bring back<br class="">support for them.<br class=""></blockquote><br class="">There are a few possible answers I can think of:<br class=""><br class="">1. Do the “obvious” thing and create a separate protocol for finite<br class="">&nbsp;single-pass sequences<br class=""><br class="">2. Decide that the combination of infinite and single-pass is rare<br class="">&nbsp;enough (/dev/urandom, temperature sensor) that it's better to just<br class="">&nbsp;ask people handling them to be careful and not, e.g., try to “count”<br class="">&nbsp;them.<br class=""><br class="">3. Decide that everything on a single-pass sequence is lazy. Since you<br class="">&nbsp;can only take a single pass anyway, people won't observe their<br class="">&nbsp;closures being called more often than necessary, which was the main<br class="">&nbsp;motivator for making map, filter, et. al eager on collections without<br class="">&nbsp;an explicit .lazy.<br class=""><br class="">Implications of #3:<br class=""><br class="">* Any “partially-formed” multipass sequences (modeling only Iterator)<br class="">would be free to expose an accurate underestimatedCount, thereby<br class="">optimizing the process of copying into an array. The lazy filter<br class="">Iterator adaptor would have an underestimatedCount of 0.<br class=""><br class="">* All algorithms that require multiple passes, such as sorted(), would<br class="">be unavailable on Iterator. &nbsp;You'd have to construct an Array (or<br class="">other MutableCollection) and sort that in-place. &nbsp;Of course,<br class="">constructing an Array from an Iterator could still go on forever if<br class="">the Iterator turned out to be infinite, which means, at some level #3<br class="">is just a refinement of #2 that makes it less error-prone.<br class=""></blockquote><br class="">Do you lean towards any of these?<br class=""></blockquote><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">Yes, #3. &nbsp;</span><br 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-stroke-width: 0px;" class=""><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">We can always make the few operations that have to be eager—such as</span><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">Array construction from an Iterator—explicit with a label or something:</span><br 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-stroke-width: 0px;" class=""><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array(claimingFiniteness: someIterator)</span><br 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-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>This makes sense. &nbsp;Finite single-pass iterators can always be added in the future if compelling use cases emerge. We’re not taking anything away. &nbsp;</div><div><br class=""></div><div>All of the code I have looked at that makes a finite assumption would be converted to require `Collection` in the new model.</div><br class=""><blockquote type="cite" class=""><div class=""><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">--<span class="Apple-converted-space">&nbsp;</span></span><br 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-stroke-width: 0px;" class=""><span 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-stroke-width: 0px; float: none; display: inline !important;" class="">Dave</span></div></blockquote></div><br class=""></body></html>