Rust and Swift (i)
Thoughts after reading the introduction to the Swift book.
I started writing these responses in a Slack channel of developers I participate in as I worked through the Swift book. I realized after a bit that it would make a better blog post than chat room content, so here we are. This is all entirely off-the-cuff: me just thinking out loud as I read; this is by no means expert opinion.
I later turned this into the first part of a whole series comparing Rust and Swift!
-
..<
â seriously?That has to be one of the most annoying operators Iâve ever seen. It ends up with cognitive noise because
<name
initially processes as âstarting a genericâ and you have to re-parse it visually and mentally. After the first chapter of the Swift book, my impression is âa poor manâs Rustâ; my gut feel based on that first pass and everything Iâve seen and read about Swift over the past two years is that itâs roughly what you would get if you took Rustâs syntax and replaced Rustâs hard safety goals with the aim of mapping to ObjC semantics. (To be fair to Apple, that interoperability was probably necessary.)
An example that jumps out at me as immediately illustrative of the difference in approach the languages take is the way you pass structures by reference vs. copy. In Swift, thatâs done via two completely distinct language constructs,
struct
s andclass
es respectively.In Rust, there is just the
struct
type to handle both of those. Theyâre immutable unless you declare them withmut
, and you can pass them via copy simply by implementing theCopy
trait
(which seems roughly analogous to Swiftâsprotocol
, but Iâve not yet dug deeply enough to see how they differ). Those things arenât baked into the language, but use simpler language building blocks to define behavior into the library.I saw someone do a write up a while back arguing that Go isnât a bad language, it just isnât a good language. My first impression of Swift, after having spent the last month with Rust, is very much along those lines.
Huh. Hereâs something that I appreciate about Rust, Haskell, and others now that I didnât before: thereâs a difference between implicitly/automatically importing a prelude or a given set of standard library functions, and having actually global functions. Does Swift actually have functions like
print
in a global namespace, as the book seems to imply, or they being imported automatically a la Rust/Haskell/etc.?Edit: it appears Swift does likewise, but that you canât access the relevant module directly. Which is halfway there.
Hmm. Why have
Double
andFloat
âjust for ObjC interop, I guess?Edit: follow-up from a conversation with a friend: itâs because you have 32- and 64-bit architectures out there; sometimes you donât want 64 bits of floating point precision for that reason. Note that Rust also has this distinction; you can declare things as
f32
orf64
.Extending the above note on
class
es andstruct
s andprotocol
s vs. Rustâs approach: the same thing is true aboutextension
, which is a distinct concept from implementing aprotocol
; again, in Rust these are both just handled with a single language construct,impl
. Thatâs not becauseimpl
is overloaded, but rather because the underlying language machinery is the same for the two things. (edited)(Iâve a feeling learning Swift is going to turn me into even more of a Rust fanboy.)
Reading the two books in close sequence like this is proving really productive mentally for thinking about how the two handle the same issues. Iâve never done anything quite like this before, and itâs fascinating.
I have an increased appreciation for Rustâs use of semi-colons to turn expressions into statements, and thereby to distinguish clearly between the two (among other things, allowing for implicit return of anything thatâs an expression).
Another interesting comparison: Rustâs
match
and Swiftâsswitch
andcase
fill the same role of pattern matching. Iâm curious to see how they differ. Does Swift do matching on arbitrary expressions?Also, I see where the syntax choices came from in both, and while I slightly prefer Rustâs, I think both make reasonably good sense; Swiftâs will understandably be more familiar to C and ObjC programmers, and thatâs a perfectly defensible approach. Seen that way, it is expanding on the C-style construct (even if itâs actually doing something substantially more sophisticated than that under the hood by being a form of actual pattern matching).