Rust and Swift (iii)

Operators, including overloading, and thoughts on brevity.

September 07, 2015 (updated March 12, 2016)Filed under Tech#programming languages#rust#rust-and-swift#swiftMarkdown source

I am reading through the Swift book, and comparing it to Rust, which I have also been learning over the past month. As with the other posts in this series, these are off-the-cuff impressions, which may be inaccurate in various ways. I’d be happy to hear feedback! Note, too, that my preferences are just that: preferences. Your tastes may differ from mine. (See all parts in the series.)

I just hit operators in the Swift book. First question: are operators special syntax, or are they sugar for protocols? (Every modern language I use or even have played with handles them as sugar for another language construct—Python, Ruby, Io, Elixir, and Rust, to name just a few ranging over a substantial variety of ages and styles.)

Oh. I did the requisite digging, and operators are functions (which is okay) defined in the global namespace (:sigh:) Swift module.1 I say “okay” rather than good because the justification offered is that this is the only way to make the operators work as binary operators between existing instances of types. But that elides the fact that, if that’s the case, it is so because of other language design decisions. This seems like a perfect place to use a protocol, but perhaps (unlike Rust’s trait) they’re not sufficiently capable to handle this? That’s an open question; I have no idea about the answer.

Interestingly, Rust has several fewer operators than Swift, even apart from those mentioned in my previous post. It drops the pre- and post-increment operators entirely (as does Python), since their results can always be accomplished in other ways with less potential for confusion. Swift keeps them, no doubt in part because most (Objective) C programs are deeply familiar with them and with idioms associated with them.

I learned a few new things about Rust’s operators as well: the Boolean || and && operators and its bitwise | and & operators differ not only in that the former are short-circuit operators and the latter are not. Obviously you can also do things like bit-wise flag operations with the latter, but the reference emphasizes the short-circuiting behavior. This makes perfect sense, but it wasn’t something I’d ever considered explicitly before.

There is no ternary operator in Rust, because of how it handles the relationship between expressions and statements. Swift keeps it. That’s an interesting reflection of differences in design: Rust dropped it because if blocks are expressions, so it’s redundant, and they have had a goal of removing unnecessary features. (See the discussion on dropping the ternary operator—with an interesting aside from Brendan Eich on JavaScript—here). Note that this is not a criticism of Swift, just an observation, though I do really like Rust’s expression-driven approach.

The ?? “nil coalescing operator”, on the other hand, I actively dislike. This seems like shorthand for the sake of shorthand, partly necessitated by the existing drive toward shorthand with optional types in Swift. Sometimes brevity can lead to decreased clarity. Eliding too much, or subsuming it into shorthand, makes the language harder to hold in your head and requires you to slow down more for parsing each line.

Nothing surprising (or different) between the standard boolean operators in the two languages.

I wonder how many times the word “concise” (or synonyms of it) appear in the Swift book? It’s increasingly clear to me reading that brevity is one of the primary design goals. Maybe it’s just me, but that actually seems a little weird. Brevity is good so far as it goes, but legibility is much better.

  1. See edit in discussion of functions and global namespace in part ii.