Swift's Range Operators

I was going to wait until I had more first-hand experience with Swift before blogging any opinions, but then I remembered this is the Internet. So here I am, late to the party, weighing in on Swift's range operators, about which I have a definite opinion.

Swift's original range operators, as defined in the first beta of Xcode 6, were:

  • x..y for a half-closed range (including x, excluding y)
  • x...y for a closed range (including both x and y)

There were lots of complaints about this choice, mostly in two categories as I recall:

  • Complaint #1: .. and ... are too easy to confuse with each other, the same way = and == are easy to confuse in C.

  • Complaint #2: .. and ... are too easy to confuse with the same operators in Ruby, which are defined with the opposite meanings.

Note that these complaints aren't about personal taste. They're about making it too easy to write buggy code.

Here is a complaint that absolutely nobody made, so please don't take it too seriously, but it did occur to me as a possible annoyance:

  • Complaint #3: Some people want ... to be a system macro that automatically gets replaced with an ellipsis character.

A few people, including me, have proposed this alternative, which I am still convinced is best:

  • x..<y for half-closed
  • x..=y for closed

Here's what I like about this option:

  • There is a parallel structure to the operators. ".." means this is a range, followed by a qualifier, either "<" or "=", that indicates whether the last element of the range is less than or equal to y.

  • Neither operator is a substring of the other. You can't make the mistake of typing one too few characters.

  • The meanings of the operators are clear from their appearance (addressing Complaint #1). You won't have to pause each time to ask yourself "Which one was the closed one again?"

  • The operators don't conflict with other languages (addressing Complaint #2). When I posted my suggestion, I didn't think either operator had a precedent in any other language. It turns out ..< is used in Groovy, but it has the same meaning there as here.

In Xcode 6 beta 3, one of the range operators was changed. As of this writing, the operators are:

  • x..<y for half-closed
  • x...y for closed

This is fine with me, although I may change my mind if I ever start programming in Ruby. By only changing one of the two operators, the Swift designers[1] leave them half-open, if you will, to Complaint #2.

I want to mention one more proposed alternative that seems nice in theory but that I don't think should be adopted:

  • [x..y) for half-closed
  • [x..y] for closed

This notation is already familiar to people with a little math, and easily learnable by anyone else. It's concise. It's unambiguous. It allows for the possibility of variations like (x..y] and (x..y).

But I think it could be open to Complaint #1. Depending on the font the programmer is using, and the resolution of their monitor, and how sleep-deprived they are, a parenthesis could maybe be mistaken for a square bracket. Or the difference might not be striking enough to register when they're eyeballing the code, looking for why the program crashed.

Furthermore, I think mismatched brackets and parentheses could cause headaches in text editors other than Xcode. When we see an expression like that, we're used to being able to double-click one of the delimiters to select the whole expression. I don't know, maybe existing text editors could easily be updated to handle that, but it seems like a potential problem to me, and I do think this kind of consideration should influence language design. It's worth looking for an option that both makes theoretical sense and plays well with the tools we use in practice.

[1] To the extent there is any such person other than Chris Lattner.

4 thoughts on “Swift's Range Operators

  1. Apple also went against the precedent of Pascal (.. is closed), which had once been dear to it.

    What really, REALLY bugs me is the prefix ! operator. The current compiler insists that it (probably all prefix operators) must have no whitespace between it and its operand. Consider

    if ! literate { // … and if !literate { // …

    Long, terrible experience has driven me to get visual separation between ! and what follows. Swift won't permit it. I can perceive a reason, like its being easier to parse (can't be the reason — if you can identify the error, you know enough to interpret it) or to put the coder on notice of its not being infix (lame compared to the disadvantage), or maybe to clue the parser about how to reduce when faced with operators that are lexically harder to distinguish — free creation of overloaded user operators could make it tricky. (I don't know how the risks work out, nor have the bandwidth to reason it out.)

    Still, unary-bang is a

  2. (damn iPad miss-intolerance)

    Illegible unary bang (it's fun to think of the unlikelihood of the phrase) is such a notorious source of serious bugs that you'd hope a language that aims at being bulletproof would allow the coder to avoid it.

  3. The no-space requirement is strange (maybe that'll change too?), and so was defining .. differently than everybody else already understands it.

  4. I remembered .. from Pascal but hadn't made the connection that the Swift definition was a reversal for Apple in a way. I feel like there's a symbolism one could read into that — "This is not your father's Apple-favored programming language", or something.

Leave a Reply

Your email address will not be published. Required fields are marked *