In my opinion, this syntax stems from a kind of "C envy" or maybe "Rust envy". We want to point at some code snippets and say we can do systems code, too.
While we do want Swift to be suitable for systems programming, our mission is different in that we want to do everything. That means this systems effort must consider the context of our existing language and as well as patching its flaws, we should reflect on and preserve its strengths.
Currently, in Swift, [SomeType]
means a heap-allocated, dynamically-resizable Array -- and until recently, that was the only Array type Swift even exposed in the standard library at all. It's a good default, because Swift is a language based on the idea that everything is copyable (by default) and many language features will make copies implicitly just as you're trying to get stuff done, so indirect storage makes those copies cheap. While you do need to be a bit careful when writing mutating algorithms, on the whole it has been an enormously successful model and we're not at the end of the road with it yet; we know there are big improvements to the ARC optimiser coming that will eliminate loads more copies, and improvements to LLVM that will either eliminate or reduce the cost of a lot of bounds checking. If you need to get stuff done, it's great - it supports all the operations an array can support, language features like for
loops and captures just work and are fast. You pretty much don't need to think about copying. Super convenient.
In Rust, let vals: [i32; 3]
denotes an inline array, but Rust's array literal syntax is completely different from ours in just about every way you can think of:
// This means an inline array.
let vals_0: [i32; 3] = [1, 2, 3];
// 1. So, does [i32] mean a resizable, heap-allocated array?
let vals_1: [i32] = [1, 2, 3];
// Nope! Error - [i32] means a slice! And you need to spell it &[i32]
// 2. Okay so the type name is Vec<i32>. There is no shorthand.
// If we write that, can we initialise it with an array literal?
let vals_2: Vec<i32> = [1, 2, 3];
// Nope! Error - expected `Vec<i32>`, found `[{integer}; 3]`
// 3. In order to create a Vec from a literal, we *also* need the vec! macro.
let vals_3: Vec<i32> = vec![1, 2, 3];
// Now it finally works.
That kind of thing may be fine (or at least tolerable) for Rust developers, but it would be supremely inconvenient to any Swift developer. Swift is supposed to be a language that is approachable to people who have never done any programming before, or who are coming from languages such as Python or Javascript that are so abstract that they might not be familiar with the difference between inline vs indirect storage. They might not be the kind of people to post on these forums, but they're out there - I've even met some of them.
I think the literal syntax should spell out that this is a different kind of array. Maybe it will cause some sniggers in certain systems programmer circles that we need to spell out these kinds of details for the newbies, but they are one of our core constituencies.