--- Title: Rust and Swift (vi) Subtitle: Collection types and the difference between syntax and semantics. Category: Tech Tags: [software development, rust, swift, rust-and-swift] Date: 2015-09-19 09:00 Series: Title: Rust and Swift Part: 6 ... 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.)][series] [series]: /rust-and-swift.html --- It kind of feels like this summarizes a *lot* of things about the overall design of Swift: > Although the two forms are functionally identical, the shorthand form is preferred and is used throughout this guide when referring to the type of an array. ---_The Swift Programming Language (Swift 2 Prerelease)_ The documentation for the various types in Rust's `std::collections` module is hilarious and great. Highly recommended. One thing that jumped out at me reading this chapter of the Swift book (though I don't think it's been explicitly discussed yet): Rust doesn't have named parameters; Swift does. There are good reasons for that in both cases, but I suspect this is one of the small details I'll miss the most in Rust. I've been spoiled by Python. Swift's `Array` type is analogous to Rust's `Vec` type (usually created with the `vec!` macro), *not* its `Array` type. Rust `Vec`s and Swift `Array`s are dynamically sized and created on the heap, whereas Rust's `Array`s are statically sized and created on the stack. Syntax for creating `Array`s in both languages is quite similar (though the results are different): - Swift: + Fixed size: `let an_array: [Int] = [1, 2, 3]` + Variable size: `var an_array = [1, 2, 3]` - Rust: + Array: `let an_array: [i32, 3] = [1, 2, 3];` + Vector: `let a_vector: Vec = vec![1, 2, 3];` That's the long form, of course; both languages have type inference, so you'd rarely write it like that. The usual form would be with the type in all of those cases: - Swift: + Fixed size: `let an_array = [1, 2, 3]` + Variable size: `var an_array = [1, 2, 3]` - Rust: + Array: `let an_array = [1, 2, 3];` + Vector: `let a_vector = vec![1, 2, 3];` Rust also adds the concept of "slices," which provide access to segments of arrays, and are heap-allocated as pointers to a given item in the array and a length (number of elements) included. `Array` operations in Swift are all pretty reasonable, and surprisingly descriptive. They remind me in a good way of Python's `list` methods. There are a *lot* of [ways to interact with `Vec`s in Rust][std::vec::Vec]. (That's not a bad thing.) A bit surprising to me was the absence of an `enumerate` method, on `Vec` itself, but then I discovered that it exists in the `IntoIter` struct in the same module, which fully implements the `Iterator` `trait`. As a result, it has an `enumerate` function returning an `Enumerate` `struct` instance. (Under the covers, I suspect Swift `Array`s just implement an `Iterable` `protocol`, which is similar to this approach in some ways.) This makes a point I'm coming back to fairly often: Rust doesn't necessarily put everything on a single object definition, but rather into a set of related `struct` or `enum` types and `trait`s. This is really powerful, but it's going to take some mental adjustment. In this way, Swift's structure and semantics are much more like the languages I'm used to than Rust's are (but even there, the use of `protocols` gives it considerable new flexibility). Note that I said *semantics*, not syntax. Swift and Rust are a great example of how very similar syntax can mask differences in semantics. (For another such example, compare JavaScript's syntax and semantics to Java's: they're superficially similar syntactically, and light years apart semantically.) Swift's `Set` type and Rust's roughly analogous `HashSet` both have a `contains` method which behaves much like Python's `in` keyword. Indeed, and perhaps unsurprisingly, the two types implement many of the same methods in general. This is perhaps to be expected given that the language around sets (as a mathematical concept being mapped down into a representation in a program) is quite standardized. Because of their stricter typing systems, both Rust and Swift require you to specify the types used in their mapping constructs (Rust has `HashMap` and Swift has `Dictionary`), though of course both can infer this as well in certain cases. At the most basic level, you can't use arbitrary (hashable) types as keys in mixed fashion like you can in e.g. Python's `dict` type, but in practice this shouldn't matter, for two reasons: 1. It's generally inadvisable to use different types for keys in the same dictionary anyway. To me, at least, that usually indicates the need to step back and think more carefully about the types and data structures I'm using. 2. For the occasional case where it *is* appropriate, I wonder if you could declare the type as generic in either Rust or Swift. I'm putting this down as a TODO item for myself to find out! I really wish that Swift used the Python-style curly-brace delimited syntax (`{'key': 'value'}`) for its dictionary literal initializers. I can see, from a syntax reason, why it doesn't: that would overload the block syntax (which Python can avoid because it's white-space delimited). But it's *really* convenient. Along similar lines, I can see why the Swift designers chose to make all iterables have literal initializers using braces (`[...]`); it makes parsing fairly straightforward. However, the result is that it's pretty difficult to see at first glance what you're dealing with. It could quite easily be an `Array`, a `Set`, or a `Dictionary`. This highlights a too-little-appreciated aspect of programming language design: *readability*. However much we programmers enjoy writing code, the reality is that we will all spend a great deal of our time---probably even a majority of it---reading it instead. Thus, while we should care about conveniences for writing code, and being overly verbose can be a pain, we should also concern ourselves with the ease of comprehending code when it is read, and the syntax and conventions a language embraces are a big part of this. The `Dictionary` type in Swift is a pretty close analog to Python's `dict`, right down to several of the method names. the same is true of Rust's `HashMap`. That's not a bad thing by any stretch of the imagination. [std::vec::Vec]: http://doc.rust-lang.org/stable/std/vec/struct.Vec.html --- - [**Previous:** The value (and challenge) of learning languages in parallel.][5] - [**Next:** Pattern matching and the value of expression blocks.][7] [5]: http://v4.chriskrycho.com/2015/rust-and-swift-v.html [7]: http://v4.chriskrycho.com/2015/rust-and-swift-vii.html