[swift-evolution] Let range operators always return empty ranges if the upper bound is smaller than the lower bound.

Kevin Ballard kevin at sb.org
Wed Jan 20 15:09:44 CST 2016


I'm a minor -1 as well. I think there's value in catching logic errors like this. I'd rather see a ..<? or ...? operator that introduces this behavior.

FWIW, the Range type doesn't actually test this at all. You can say `Range(start: 2, end: 1)` just fine, since Range can be used with elements that aren't Comparable. It's just an overload on ... and ..< for Comparable elements that adds the check.

Also, if we change Range, we'll also need to change ClosedInterval and HalfOpenInterval (both of which include the end >= start check in their initializer, since they maintain an invariant that end >= start, rather than checking in the ... / ..< operators). But unfortunately, this means that the only way to make `2...1` work for ClosedInterval is to relax the invariant that says that end >= start, and I don't feel comfortable doing that. I think that invariant is important to maintain.

The end result of all this is I think we can safely introduce ..<? / ...? operators for Range that require a Comparable element, which make the end of the range equal to the start if it would otherwise be less (because `Range(start: 2, end: 1)` isn't actually empty, instead it contains all values starting at two and incrementing until wraparound hits 1). But the operators wouldn't be able to produce intervals, and wouldn't work for non-comparable elements (the normal ..< / ... operators work just fine on non-comparable elements already). Basically, something like

public func ..< <Pos : ForwardIndexType where Pos : Comparable>(start: Pos, end: Pos) -> Range<Pos> {
  return Range(start: start, end: max(start, end))
}

public func ... <Pos : ForwardIndexType where Pos : Comparable>(start: Pos, end: Pos) -> Range<Pos> {
  let end = max(start, end)
  _precondition(end.successor() > end, "Range end index has no valid successor")
  return Range(start: start, end: end.successor())
}

-Kevin Ballard

On Wed, Jan 20, 2016, at 11:42 AM, Jordan Rose via swift-evolution wrote:
> I'm a minor -1; it feels like this is in the same family as nil-messaging in that it can silently treat invalid input as a no-op. I'm not convinced that "upper bound less than the lower bound" is a strong enough signal for "empty" rather than "logic error". But it seems I'm in the minority.
> 
> Jordan
> 
> 
> > On Jan 19, 2016, at 12:46, Uwe Falck via swift-evolution <swift-evolution at swift.org> wrote:
> > 
> > I’m looking for feedback on this request if its worth to start an evolution proposal.
> > 
> > 
> > Let range operators always return empty ranges if the upper bound is smaller than the lower bound.
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution


More information about the swift-evolution mailing list