> On 6 Sep 2016, at 07:39, David Hart via swift-evolution
> <swift-evolution@swift.org> wrote:
>
> 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
>
> Or am I missing something?
>
> On 6 Sep 2016, at 08:15, David Hart via swift-evolution
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
>> Hi people,
>>
>> 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:
>>
>> struct Day { … }
>> struct Day : Comparable { … }
>> struct Day : Strippable { … }
>>
>> struct Info {
>> let name: String
>> let range: Range<Day>
>> }
>>
>> Info(name: "Christmas Vacation", range: twentyfith...thirtyfirst)
>> Info(name: "Summer Vacation", range: someday..<otherday)
>>
>> 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?
>>
>> protocol RangeType {
>> associatedtype Bounds
>> let lowerBound: Bound { get }
>> let upperBound: Bound { get }
>> // what else? not even sure if it is possible to define such a protocol
>> }
>>
>> David.
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.
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:
// Reintroduce these methods that were lost in the new indexing API
protocol ForwardStep { func successor()? -> Self }
protocol BackwardStep : ForwardStep { func predecessor()? -> Self }
// Enable conversion of ranges
extend ClosedRange where Self.Bound : ForwardStep {
func toOpenRange() -> Range<Self.Bound>? {
guard let upperBound = self.upperBound.successor() else {
return nil }
return self.lowerBound ..< upperBound
}
}
extend Range where Self.Bound : BackwardStep {
func toClosedRange() -> ClosedRange<Self.Bound>? {
guard let upperBound = self.upperBound.predecessor() else {
return nil }
return self.lowerBound ... upperBound
}
}
extend ClosedRange where Self.Bound : BackwardStep {
init(_ openRange:Range<Self.Bound>)? {
guard let closedRange = openRange.toClosedRange() else { return
nil }
self = closedRange
}
}
extend Range where Self.Bound : ForwardStep {
init(_ closedRange:Range<Self.Bound>)? {
guard let openRange = closedRange.toClosedRange() else { return
nil }
self = openRange
}
}
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.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution