Swift observations from a reluctant Rustacean
November 16, 2024
Recently I've been thinking about Swift in terms of Rust, & have appreciated anew some of the choices made. In Rust. There's been a proliferation of X vs Y posts on the web, especially since the advent of LLM AI, so I try to resist the format. It's often easier for me to think about a programming language in terms of another programming language though, & some comparisons seem inevitable.
In Swift, value types like structs are cloned rather than moved (to use Rust terms). Built in types only do this when something changes, & arrays are the most obvious example of this copy on write optimisation. But for a struct that you or I might write the cloning always happens. Every time. Every time you pass your struct to another variable, in a function call say, unless you were to wrap your struct in a reference type & write your own copy on write implementation, you'd get a whole new copy. Every, single, time. In Rust cloning is manual, & only needs to happen if the value's going to be re-used as well as moved. For library authors I guess especially in Rust there's also the Cow type, Cow standing of course for copy on write.
Reference types in Swift use ARC (atomic reference counting).
Edit 17 November 2024 – A for Atomic in Rust. A for Automatic in Swift. Though Swift ARC also uses atomic operations for its reference counting. A for argh-proofreading.
I suppose that's because the last iterations of Objective-C used ARC, & Swift was designed to be a drop-in replacement. Oddly enough I remember a lot of resistance to using ARC from amongst Objective-C devs at the time, but officially at least that's how it worked. Arc<T>, the slower version of Rc<T> allows for shared ownership that's thread safe, in Rust. In Swift, where all references are shared & potentially mutable, it's not necessarily thread safe at all. Would separate Rc & Arc implementations in Swift make more sense now? Maybe. But look at the resistance to Swift 6 & I think you might get an appreciation of the chance of that happening. As it is the more expensive atomic counting happens all of the time in Swift.
Lastly, errors. Returning error Results seems to be more consistent & somewhat better thought out in Rust. Swift's dual use of throwing & returning Results, with optionals sometimes also returned, is far muddier.
All of this isn't to denigrate the design choices made with Swift, or how people use it. All of these choices are trade-offs after all. Rather it's meant to be hopeful about my own Rust programming. I recently picked up a copy of Rust for Rustaceans, which is meant to be for intermediate Rust programmers, & oh boy. Intermediate? One day maybe. I've been a beginner Swift programmer for ten years now, & an ocassional & very much beginner Rust programmer for at least eight. But for now, if I do these things, and better than these things, then my resulting Rust code will be at least as good & at least as fast as the Swift equivalent, & potentially a whole lot better & faster, because this level of optimisation seems like low hanging fruit. But this comparison isn't just about the end product. Or even the craft of it all. Rust has one advantage it seems Swift can never have.
I recently wrote, "Even if the only thing Rust had going for it was that it wasn't beholden for its existence to one of the giant tech companies that would still be a lot." Those chickens have now come home to roost. The US has had its election, & all of us are left to deal with the fallout from that. Tim Cook didn't need to rush to congratulate the President-elect. But he did.
Do not adjust your sets
August 6, 2024
I'm deep in the depths of a Canberra winter & I've been messing around with the styles on this site for my amusement. As they used to say on the idiot box: do not adjust your sets.
I've been continuing on my minimalism kick. I got rid of the custom font files, which means most pages on the site now weigh in at around 30 instead of 100KB. On the horror show that is the modern web if those were megabytes instead nothing would seem out of place.
The font combinations are from the Modern Font Stacks site, & some of those should be on most devices already.
I've been thinking some more too about the Gemini Protocol, & maybe moving a copy of this site into that world. The heyday of Gemini was probably during the lockdowns, but it still feels like it might be worth it. The aesthetics are certainly a good fit for me.
Elixir and Rust - Mea culpa, mea maxima culpa
July 21, 2024
I've been down on Rust lately. Unfairly so. I may even have said – what I totally did say was – "Rust is a terrible language for game development. Probably a terrible language for any app with a GUI right now. Again there are things to like, but more things not to."
Mea culpa, mea maxima culpa. Rust can be a terrible language. It can certainly be used terribly. Lord knows, I've tried. But for the right sort of problem. Where the solution to the problem's framed in the right sort of way… it can work well. It does have a lot going for it. More than I may have implied (than I totally, literally said).
Even if the only thing Rust had going for it was that it wasn't beholden for its existence to one of the giant tech companies that would still be a lot. C# is only ever going to be as open source as Microsoft wants it to be. Kotlin is only ever going to do what Google tells JetBrains to do with it, and theirs is the only Kotlin IDE in town. Swift got result builders because Apple wanted them, & when Apple says jump the answer isn't ever going to be anything but a gung ho "how high?" But the problem Rust is used to solve has to be framed just so.
All of the pain (& a lot of the payoff) in Rust revolves around its rules for references. Any number of read-only ones, or just the one at any one time if it's a mutable reference. Which is fine if the problem's simple. Or small. Or both. It gets harder to do when a problem's large & changing as it's solved, which is what happens often in game development, but it can probably be done.
Rust is not the solution to every problem, & it is galling – which was the source of my, ahem, recent outburst… s (plural) – to be forced to jump through hoops when the business logic prevents the kind of race condition this is all meant to prevent from ever occurring any way. But that's probably a function of breaking up the problem the wrong way. Possibly. It's a baby/bathwater situation, not any kind of breach.
There's a great explanation of ownership on without.boats I read recently, in References are like jumps, & Ownership, that I wouldn't even attempt to summarise here. Interestingly Mojo & Lattner come up again in the context of value semantics. Less flatteringly, as you might guess.
While I'm at it…
The Elixir community on Reddit sucked, but is probably not necessarily all that representative of the Elixir community generally. I have been tempted by the language once or twice again over the years since bad mouthing it here & flouncing away from it. I could never really find a problem big enough to warrant solving with what Elixir brings to the table, but small enough that it couldn't already be done with some combination of other more readily available tools though. Add Redis for caching, Systemd for restarts, or whatever, & most any server-side language can do what Elixir does without having to leave the mainstream behind. (This may not be helping…)
I used Elixir in anger when I self hosted an instance on the Fediverse. That was with Akkoma. I never dug too deeply into the code, & was luckily never personally a victim of "Akkoma Database Rot", where the database gradually falls apart because of some strange schema/JSON choices made with it, so while I don't think I'd recommend it, for the short time I ran it, it ran OK. It wasn't the problem with self hosting.
I did also write a toy Gemini server in Elixir for fun just the other week. But I also wrote one in C#, Go, Python, Ruby, Rust & Swift too. I was interested in playing around with how the different languages deal with TCP & TLS connections, & with the Gemini Protocol. This is Gemini the minimalistic Gopher-like set up, not Gemini the Google AI model. It's really a very small thing a Gemini server, perfect to play with.
But none of that makes me an Elixir developer any more than it makes me a Go developer. Just a curious one. That much hasn't changed.