my php website :D https://j0.lol
at main 175 lines 7.1 kB view raw
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&lt;N, T&gt;</code>, which acts like... an array. In Rust 19 terms, the normal Swift array is similar to a 20 <code>Arc&lt;Vec&lt;T&gt;&gt;</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..&lt;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&lt;T&gt;</code>, 111 adding copy-on-write with <code>Cow&lt;T&gt;</code>, or reference counting 112 with <code>Rc&lt;T&gt;</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>