<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="">Hello,<div class=""><br class=""></div><div class="">I'd like to discuss the opportunity to extend the Swift Standard Library with a new protocol and a family of concrete types.</div><div class=""><br class=""></div><div class="">The problem: Sequence and IteratorProtocol do not throw. They are unsuitable for external resources like database rows, file contents, socket bytes, etc. That's a pity, because the Standard Library provides a full suite of methods like map, flatMap, filter, first, reduce, etc that are both useful, and unavailable for I/O sequences.</div><div class=""><br class=""></div><div class="">This email provides the first draft for a new protocol, Cursor, and a family of reusable methods and concrete types that help handling untrustable sequences.</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(79, 129, 135);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">let</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> cursor = </span><span style="color: rgb(0, 132, 0);" class="">/* Cursor of Int */</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">while</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> int = </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">try</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">cursor</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #31595d" class="">next</span><span style="font-variant-ligatures: no-common-ligatures" class="">() {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #3e1e81" class="">print</span><span style="font-variant-ligatures: no-common-ligatures" class="">(int)</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div></div><div class=""><br class=""></div><div class="">Ideally, the Swift compiler would provide sugar for Cursor, and let the user write:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal; color: rgb(0, 132, 0);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">// Handle errors in both cursor creation and iteration, in a single `for` statement</span></div><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">for</span><span style="font-variant-ligatures: no-common-ligatures" class=""> <span style="color: rgb(186, 45, 162);" class="">try</span> int </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">in</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="color: rgb(186, 45, 162);" class="">try </span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(49, 89, 93);" class="">makeCursor</span><span style="font-variant-ligatures: no-common-ligatures;" class="">()</span> {</div><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #3e1e81" class="">print</span><span style="font-variant-ligatures: no-common-ligatures" class="">(int)</span></div><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div></div></div><div class="">Cursor share traits from both LazySequenceProtocol and IteratorProtocol, but differs in several ways:</div><div class=""><br class=""></div><div class="">- Cursor types are classes, and have a lifetime. This is because Cursor aims at wrapping external resources, and has a non-mutating iteration method (because it is the external resource that mutates on iteration).<br class="">- Cursor iteration may throw errors.<br class="">- A cursor can not be repeated.<br class=""></div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(186, 45, 162);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">public</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span><span style="font-variant-ligatures: no-common-ligatures" class="">protocol</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> Cursor : </span><span style="font-variant-ligatures: no-common-ligatures" class="">class</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 116, 105);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span><span style="font-variant-ligatures: no-common-ligatures" class="">/// The type of element traversed by the cursor.</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(186, 45, 162);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span><span style="font-variant-ligatures: no-common-ligatures" class="">associatedtype</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> Element</span></div><p style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><br class="webkit-block-placeholder"></p><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 116, 105);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span><span style="font-variant-ligatures: no-common-ligatures" class="">/// Advances to the next element and returns it, or nil if no next element</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 116, 105);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span><span style="font-variant-ligatures: no-common-ligatures" class="">/// exists. Once nil has been returned, all subsequent calls return nil.</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> next() </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">throws</span><span style="font-variant-ligatures: no-common-ligatures" class=""> -> Element?</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class="">Cursor can implement the classic contains(_:), contains(where:), enumerated(), first(where:), flatMap(ElementOfResult), flatMap(SequenceOfResult)</span>, flatMap(CursorOfResult), forEach(_:), joined(), map(_:), etc.</div><div class=""><br class=""></div><div class="">Like lazy sequence, Cursor.filter, map, flatMap, etc return other cursors.</div><div class=""><br class=""></div><div class="">One can derive an Array from a cursor, with <span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures; color: rgb(186, 45, 162);" class="">try</span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class=""> </span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);" class="">Array</span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class="">(</span><span style="color: rgb(79, 129, 135); font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class="">cursor</span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class="">)</span>.</div><div class=""><br class=""></div><div class="">This is enough for a pitch, and grab your comments, if you find that Cursor would be a nice addition to the Standard Library.</div><div class=""><br class=""></div><div class="">There is already a working implementation of Cursor, that fuels the manipulation of database results in the next version of the <a href="https://github.com/groue/GRDB.swift/pull/148" class="">GRDB.swift</a> library: see <a href="https://github.com/groue/GRDB.swift/blob/fc1fdab51a91dedc7f5233b32440f8e8411cdf0a/GRDB/Core/Cursor.swift" class="">https://github.com/groue/GRDB.swift/blob/fc1fdab51a91dedc7f5233b32440f8e8411cdf0a/GRDB/Core/Cursor.swift</a></div><div class=""><br class=""></div><div class="">Gwendal Roué</div><div class=""><br class=""></div></body></html>