<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 6 Sep 2016, at 07:39, David Hart via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="content-type" content="text/html; charset=utf-8" class=""><div dir="auto" class=""><div class=""><div style="direction: inherit;" class=""><div style="direction: inherit;" class=""><span style="background-color: rgba(255, 255, 255, 0);" class="">I have the impression we exchanged flexibility for correctness (the ability to represent 0..<Int.max) and that it's wasn't worth the loss of flexibility.1</span></div><div style="direction: inherit;" class=""><span style="background-color: rgba(255, 255, 255, 0);" class=""><br class=""></span></div><div style="direction: inherit;" class=""><span style="background-color: rgba(255, 255, 255, 0);" class="">Or am I missing something?</span></div></div></div><div class=""><br class="">On 6 Sep 2016, at 08:15, David Hart via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:<br class=""><br class=""></div><blockquote type="cite" class=""><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class="">Hi people,<div class=""><br class=""></div><div class="">I’ve recently started migrating some Swift 2 projects to Swift 3. I came across the split of Range into Range and ClosedRange and I’ve really struggled with it. Specifically, in Swift 2, I had a struct with a Range property that was initialised in many places with either a closed or open range:</div><div class=""><br class=""></div><div class=""><div class=""><font face="Menlo" class="">struct Day { … }</font></div><div class=""><font face="Menlo" class="">struct Day : Comparable { … }</font></div><div class=""><font face="Menlo" class="">struct Day : Strippable { … }</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">struct Info {</font></div><div class=""><font face="Menlo" class=""> let name: String</font></div><div class=""><font face="Menlo" class=""> let range: Range<Day></font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">Info(name: "Christmas Vacation", range: twentyfith...thirtyfirst)</font></div><div class=""><font face="Menlo" class="">Info(name: "Summer Vacation", range: someday..<otherday)</font></div></div><div class=""><br class=""></div><div class="">Now, in Swift 3, it seems like we’ve lost a type to represent any range to allow an API client the flexibility to specify it as he wishes. Is there a solution to this problem through a protocol which both ranges conform to, or are we stuck with this because of the new API?</div><div class=""><br class=""></div><div class=""><font face="Menlo" class="">protocol RangeType {<br class=""> associatedtype Bounds<br class=""> let lowerBound: Bound { get }<br class=""> let upperBound: Bound { get }<br class=""> // what else? not even sure if it is possible to define such a protocol<br class="">}</font></div><div class=""><br class=""></div><div class="">David.</div></div></blockquote></div></div></blockquote><br class=""></div><div>The problem was that to implement both generically, a closed range was just an open range with the upper bound increment by one step, but as you say this wasn't safe as Int.max etc. could not be used.</div><div><br class=""></div><div>I think if you wanted to solve this you'd need to reintroduce the concept of incrementing by a minimum step, which was moved away from index types during the changes to the new indexing model for collections. You could do this something like so:</div><div><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><font face="Monaco" class="">// Reintroduce these methods that were lost in the new indexing API</font></div><div><font face="Monaco" class="">protocol ForwardStep { func successor()? -> Self }</font></div><div><font face="Monaco" class="">protocol BackwardStep : ForwardStep { func predecessor()? -> Self }</font></div><div><font face="Monaco" class=""><br class=""></font></div><div><font face="Monaco" class="">// Enable conversion of ranges</font></div><div><font face="Monaco" class="">extend ClosedRange where Self.Bound : ForwardStep {</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>func toOpenRange() -> Range<Self.Bound>? {</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">                </span>guard let upperBound = </font><span style="font-family: Monaco;" class="">self.upperBound.successor() else { return nil }</span></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">                </span>return self.lowerBound ..< upperBound</font></div><div><span style="font-family: Monaco;" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</span></div><div><font face="Monaco" class="">}</font></div><div><font face="Monaco" class="">extend Range where Self.Bound : BackwardStep {</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>func toClosedRange() -> ClosedRange<Self.Bound>? {</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">                </span>guard let upperBound = </font><span style="font-family: Monaco;" class="">self.upperBound.predecessor() else { return nil }</span></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">                </span>return self.lowerBound ... upperBound</font></div><div><span style="font-family: Monaco;" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</span></div><div><font face="Monaco" class="">}</font></div><div><font face="Monaco" class="">extend ClosedRange where Self.Bound : BackwardStep {</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>init(_ openRange:Range<Self.Bound>)? {</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">                </span>guard let closedRange = openRange.toClosedRange() else { return nil }</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">                </span>self = closedRange</font></div><div><span style="font-family: Monaco;" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</span></div><div><font face="Monaco" class="">}</font></div><div><font face="Monaco" class="">extend Range where Self.Bound : ForwardStep {</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>init(_ closedRange:Range<Self.Bound>)? {</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">                </span>guard let openRange = closedRange.toClosedRange() else { return nil }</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">                </span>self = openRange</font></div><div><span style="font-family: Monaco;" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</span></div><div><font face="Monaco" class="">}</font></div></blockquote><div><br class=""></div><div>I've rushed this a bit so forgive any glaring errors, but this is essentially how I'd bolt this on right now myself. Basically it reintroduces some of the flexibility, but with the safety of optionals to avoid the previous problem of incrementing a maximum value, this shouldn't be a problem for performance since it's just being used for conversion.</div></body></html>