1<?php speech_start(SpeechCharacter::Deer, SpeechEmotion::Neutral); ?>
2<p>
3 Going to preface this post with this: I'm not a programming language
4 designer. I don't really know what I'm talking about. I'm just a Rust
5 developer with a passing interest in Swift. I probably made some mistakes in
6 here, feel free to send me corrections.
7</p>
8<?php speech_end(); ?>
9
10<p>
11 So about a week ago, I was bored and watching WWDC 25 (pronounced "dub dub
12 DC", apparently.) I was watching this video:
13 <a href="https://developer.apple.com/videos/play/wwdc2025/312"
14 ><em>Improve memory usage and performance with Swift</em></a
15 >, where they show off some new features in Swift to reduce memory overhead
16 and increase safety (feel free to watch this alongside!) The first new
17 standard library construct they show off is
18 <code>InlineArray<N, T></code>, which acts like... an array. In Rust
19 terms, the normal Swift array is similar to a
20 <code>Arc<Vec<T>></code>, where it is a growable collection that
21 can be shared across threads and is copied on write. To keep the analogy
22 going, the new Swift <code>InlineArray</code> is like a Rust array:
23 <code>[T; N]</code>. To make it clear, <code>Array</code> is heap-allocated
24 and <code>InlineArray</code> is stack-allocated.
25</p>
26
27<pre><code class="language-swift"><!--
28func array() {
29 var array = [4, 5, 6]
30}
31
32func inlineArray() {
33 var array: InlineArray<3, Int> = [4, 5, 6]
34}
35--></code></pre>
36
37And let's compare to Rust:
38
39<pre><code class="language-rust">
40fn vec() {
41 // I could wrap this in an Arc, but
42 // that's not really what real code would do.
43 let mut vec = vec![4, 5, 6];
44}
45
46fn array() {
47 let mut arr = [4, 5, 6];
48}
49</code></pre>
50
51<p>
52 You can probably see the argument I'm going to make here — This is less
53 ergonomic. Rust is often said to have bad syntax, but here you can see that
54 the better performing option is <em>just easier</em> than the heap-allocated
55 version.
56</p>
57
58<h2>Safety</h2>
59
60<p>
61 So another topic in the video is how to efficiently read from a reference
62 counted collection. In order to avoid the reference counter, and read data
63 directly, one would previously use an unsafe pointer to do a direct read.
64</p>
65
66<figure>
67 <pre><code class="language-swift">
68 // Safe usage of a buffer pointer
69 func processUsingBuffer(_ array: [Int]) -> Int {
70 array.withUnsafeBufferPointer { buffer in
71 var result = 0
72 for i in 0..<buffer.count {
73 result += calculate(using: buffer, at: i)
74 }
75 return result
76 }
77 }
78 </code></pre>
79
80 <figcaption>Example from above WWDC talk, used as a reference.</figcaption>
81</figure>
82
83<p>
84 As highlighted in the talk, these buffers are unsafe partially because they
85 could be used outside of the scope of the function (e.g. returned, or stored
86 as part of a structure), and misued. In order to make this operation safe,
87 they introduce a type called <code>Span</code>, which points to a
88 contiguious block of memory. In order to make this safe, a new "Marker
89 trait" (Rust speak) called <code>Escapable</code><a ref="escapable"></a>
90 is added to the language. This trait is auto-added to all types by default,
91 and you can specify if your type cannot be used outside of its context with
92 <code>~Escapable</code>. Pretty neat language feature!
93</p>
94
95<p>
96 This is a very different approach to Rust. We deal with pointer unsafety by
97 relegating them to <em>Unsafe Rust</em>, a language that lives alongside
98 <em>Safe Rust</em>. But also — We sidestep this whole problem.
99 <code>Vec</code>s are not reference-counted (you have to wrap them in a
100 <code>Rc</code> or <code>Arc</code> for that,) so we don't have to sidestep
101 the reference counter.
102</p>
103
104<h2>Conclusion</h2>
105<p>
106 You can clearly see the difference in these language's designs from these
107 two examples. Swift makes working with types as easy as possible, while
108 letting you "drop down" for performance. Rust instead makes the most
109 ergonomic pattern the most performant, while letting you "build up"
110 convenience by moving to heap allocation with <code>Vec<T></code>,
111 adding copy-on-write with <code>Cow<T></code>, or reference counting
112 with <code>Rc<T></code>.
113</p>
114
115<p>
116 I think it's clear who these language features are for — Swift library
117 maintainers. Being able to write more performant code for your users will
118 make everyone happy, and doing this without unsafety is nice. I don't think
119 this is really for app developers, or anything like that. Making all of your
120 array accesses use spans to dodge the reference counter is
121 <em>technically</em> faster, but makes things much more annoying to maintain
122 than the obvious solution. I think the talk makes this clear, as they show
123 off a new
124 <a href="https://github.com/apple/swift-binary-parsing"
125 >Binary Parsing library</a
126 >
127 at the end which uses these new language features.
128</p>
129
130<p>
131 As for the title of this article. I don't think Swift is becoming
132 unergonomic Rust (<a
133 href="https://en.wikipedia.org/wiki/Betteridge%27s_law_of_headlines"
134 >Betteridge's law of headlines</a
135 >
136 wins again.) It's just bringing in features similar to Rust to "drop down"
137 to. Honestly, a "less complex" Rust has a good place in the world of
138 programming languages. There is some work adjacent to this, see the
139 <a href="https://github.com/softdevteam/alloy">Alloy language</a>: a fork of
140 Rust that gives you opt-in garbage collection for things like Linked Lists.
141 I think it's easy to write things like this off — but all languages have
142 their tradeoffs. What makes you a good developer is being able to take all
143 of the values of prospective systems and being able to pick the right one<a
144 ref="values"
145 ></a
146 >!
147</p>
148
149<footer>
150 <h2 id="notes_heading">Footnotes</h2>
151 <ol>
152 <li id="note_escapable">
153 So Swift calls traits <em>Protocols</em>, and this one is implicitly
154 applied to all Swift types. Here's
155 <a
156 href="https://github.com/swiftlang/swift-evolution/blob/main/proposals/0446-non-escapable.md"
157 >SE-0446</a
158 >
159 if you want to read into it further. In Rust, we would make a trait,
160 and then have a
161 <a
162 href="https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods"
163 ><em>blanket implementation</em></a
164 >
165 over a generic. Dunno how Swift does this!
166 <!-- <a aria-label="Return to content">↩</a> -->
167 </li>
168 <li id="note_values">
169 Bryan Cantrill has a great talk on this:
170 <a href="https://youtu.be/Xhx970_JKX4"
171 ><em>Platform as a Reflection of Values</em></a
172 >
173 </li>
174 </ol>
175</footer>