The Problem with Swift

jolon
11 min readJun 7, 2023

I originally wrote this article in late 2021 and never published it. It’s been sitting in my drafts for 18 months and I thought it would be good to release it. With Swift adding support for if and switch expressions it gives me some hope that Swift might have better long term prospects. Nonetheless I thought I would release this article for posterity. I’ve added an Addendum with some additional thoughts on Chris Lattner’s new Mojo/Python programming language at the end.

According to Wikipedia, Swift was started by Chris Lattner in 2010 and first released in 2014.

In that era (2010–2014) the development world really wasn’t ready for a functional language. The main objective for Swift was memory safety. Objective-C was just C with a message passing runtime, so memory safety was a bit of an issue. Over the years Apple (and largely through Chris Lattner) had done a great job using LLVM to provide memory analysis which also led to automatic reference counting (ARC).

Memory safety, the wrong focus

Given Apple’s consumer focus, memory safety is understandably a priority. Chris Lattner, who had spent so much time on memory safety with Objective-C, thought the next logical step was a brand new syntax that took memory safety to the next level. Not only would developers be aided in preventing memory errors, they would be prevented from making memory errors!

At the time the world wasn’t ready for a functional programming language. In fact the world was barely ready for Objective-C and developers were only just starting to become comfortable with it.

So Swift was a familiar language, a kind of clean Java-like syntax, effectively a better and more modern Objective-C.

The timing of Swift though was somewhat unfortunate. Languages take time to mature and even though Swift was released in 2014 it wasn’t really hitting it’s stride until a few years later.

But in that intervening time, functional languages became more popular. Even Apple was recognising this with Swift. In 2019 Apple introduced both the Combine framework and SwiftUI. Combine is a functional framework in a similar vein to RxSwift, which had been introduced all the way back in 2015, only a year after the first release of Swift.

Clearly Apple, sometime prior to 2019, was beginning to realise the importance of functional programming.

Swift is not a functional language

The big problem though is that Swift is not a functional language.

In Swift control structures are just that, control structures. If, switch, for, etc. can’t return a value. There is no implicit return of the last value in a block. There is pattern matching, but only for tuples, not for structs, classes, arrays, or dictionaries.

(Edit 2023: Swift 5.9 allows if and switch to be used as expressions)

It is clear however that Apple are heading in the functional direction. With new functions being added to core objects like Array.

The big problem though is that Swift just isn’t a functional language. And this is a big problem because developers now have access to a plethora of languages that have much better functional support.

For web development even JavaScript has better functional support, and there is a plethora of languages which compile to JavaScript which provide even better support like Elm, Clojure, and Facebook’s ReasonML. For server applications there is Elixir/Erlang and Rust. Even Kotlin has better support for functional programming than Swift.

The problem for Apple is that a large number of developers are experiencing the benefits of functional programming in these other environments and expect the same in the Apple ecosystem. However, in the Apple ecosystem there are only two choices: Objective-C and Swift. And in reality Objective-C is becoming less of an option, for example SwiftUI can’t be used from Objective-C.

Swift won’t become a functional language

One response to this dilemma would be to simply make Swift more functional. Even though that is not outside the realms of possibility I think it is highly unlikely. As mentioned above, control structures don’t return a value. Swift isn’t likely to change its core syntax behaviour (although it did in the early days). So the only option would be to add a new parallel functional syntax, but given the monstrosity Swift already is, I think this is also highly unlikely.

(Edit 2023: As noted above if and swift are now expressions, so this gives me some hope)

Apple’s options

Swift was an interesting decision by Apple. A brand new language from scratch is an ambitious undertaking. In reality it was Christ Lattner who conceived the language and brought it to fruition. It is unlikely Apple today would start a brand new language internally from scratch (not to mention it would need to continue to support Swift for a number of years).

I think Apple would need to adopt another language. At the top of the list would have to be Rust. Rust is compelling because it is effectively a C/C++ replacement, even an entire operating system including the microkernel has been implemented in Rust (Redox), yet Rust supports many high level functional paradigms.

An interesting question is why didn’t Apple just use Rust instead of Swift? Rust was announced in 2010 around the same time Christ Lattner started on Swift. However, Rust did change dramatically in the early years, particularly in how memory was handled. Chris Lattner no doubt had strong opinions on this and perhaps more experience than anyone in the industry. In fact it could be argued Swift has some of the best memory safety features. However, memory safety is largely a done deal these days, developers are after more, and unfortunately Swift didn’t deliver in these other areas. In all fairness developers probably weren’t ready for a non-imperative language in 2014, but they were not long after, which is unfortunate timing.

In hindsight Apple probably would’ve been better off continuing to improve Objective-C, which is what it probably would’ve done if Lattner hadn’t come up with Swift. Objective-C was already improving with more concise syntax and features like ARC (and before that garbage collection). An Objective-C 3.0 would have been released which would’ve kept developers happy for a few more years. Not to mention that Objective-C has the nice feature that it is just C and interfaces directly with C libraries, which is something Swift can’t do. In fact there are some Apple libraries which suggest not using Swift at all, for example if you are sending audio data to an audio driver.

If Apple had’ve waited a few years, Rust probably would’ve been the logical alternative. Although, despite the Swift monstrosity the syntax is still cleaner than Rust.

A higher level language

It’s impressive that Rust provides such high level features whilst effectively being a C replacement. However, there is no need in this day and age to be restricted by a language which is effectively a C replacement. In fact in 1981, when Objective-C was released, C performance was eschewed in favour of the flexibility of Objective-C’s message passing runtime, which actually allows Objective-C calls to be made even over a network!

Swift also is nowhere near as fast as C. Swift is a lose-lose language. It’s not high-level or advanced enough, whilst not being low-level or performant.

How much more so is a high level language acceptable today than it was 40 years ago! I see no reason why the majority of code couldn’t be written in an interpreted language like Python or Ruby. And we see this in fields like data science, machine learning, web development, and parts of game development.

MacRuby

Interestingly Apple was heading in this direction before Swift. In 2008 Apple released MacRuby which had bindings to Objective-C, it was effectively an Objective-C replacement. In my opinion the desktop developer world probably wasn’t ready for Ruby in 2008. There was a buzz at the time around Ruby-on-Rails and every web framework was copying it. But Ruby the language still had a fairly small uptake. Most people were still familiar with Java or C or PHP.

Nonetheless Apple was clearly moving in this direction of apps being written in a high level interpreted language. MacRuby development ended in 2011. I wonder how much this had to do with Lattner’s Swift? (I’m not saying it did, but the timing is interesting)

I think Apple should revisit a high-level interpreted language. Interpreted languages have the advantage of not needing a build process, they can be edited easily, even at runtime. Interpreted languages also have the ability to be freed from the minutiae of memory management.

I’ve written about this before, but I’d love to see an application development environment where users/developers can edit code at runtime. In my view this is most easily achieved with an interpreted language. A downside to interpreted languages is performance, but as mentioned, I don’t see this as an issue for most use cases. And if performance is an issue the interpreted language can call out to a compiled lower level language, like Rust.

(Edit 2023: See my Addendum below on Python/Mojo)

Conclusion

Apple’s ecosystem is sufficiently compelling that it can’t be ignored (as much as we’d like to). And it’s very difficult to build products that seamlessly integrate with Apple’s ecosystem without using Swift.

However, Swift is a lose-lose, it’s not high-level or modern enough, and not low-level or performant enough. Rust beats it in both high-level features and low-level performance and integration.

The result, I believe, is that developers will reluctantly use Swift. They will only use it because they have to, not because they want to. This is a problem for Apple. You need to keep your developers happy.

One possibility is that there could be a grass roots alternative. There are a few Rust libraries with Objective-C bindings already. With regards to a high level language there are no clear contenders. I think the target for such a language is for GUI applications. And perhaps there is no ideal scripting language for GUIs at the moment. I can’t see Apple developing one from scratch (the closest is possibly AppleScript or maybe JavaScript), but neither are ideal and quite dated.

So the ball is in Apple’s court, it will be interesting to see what they do. Because Swift is still somewhat impressive, a massive undertaking, and still relatively new, it would be a bold move to introduce a replacement. It’s ironic that Apple are finding themselves in the same situation they were in in 2014, an outdated language (i.e. Objective-C), and only 7 years later they are in the same position with another outdated language.

Addendum — Python/Mojo (2023)

I’ve been a bit harsh on Chris Lattner in some of my articles. Where has he been, AWOL? Obviously he left Apple, went to Google and a few other companies. He focussed on Swift for TensorFlow at Google which had some great features but the project has now been completely disbanded after he left Google. Meanwhile Swift seemed to stall as well…

Well, turns out Lattner started a company called Modular and one of their products is a new programming language called Mojo which is a superset of Python.

The curious thing about Lattner building a Python compiler is that in his second interview with Lex Fridman, Lex was talking about how he likes Python, and Lattner was kind of squirming defending Swift. So some time between that interview and today Lattner had an epiphany and decided to go all in on Python.

Lattner’s motivation for embracing the Python syntax is revealed in Lex’s third interview with him. Given Lattner’s primary focus on machine learning, the field had almost entirely adopted Python. So it was a pragmatic choice for him.

What is curious about Mojo, is that it isn’t just a fast Python for ML, it’s designed to be a systems programming language. It’s kind of bizarre to think of Python as a systems language, but indeed that is what Mojo is. Mojo adds some extra features like static typing and structs to achieve this.

Systems languages is Lattner’s speciality with LLVM and Clang. So if anyone could pull off a systems language with Python syntax it would be Lattner.

This dovetails nicely with my thoughts above about whether Apple really just needs a high level language. Swift already isn’t that performant and yet is kind of difficult to use. I mentioned Python above as a GUI programming language. Interestingly with Mojo you could have the best of both worlds.

One challenge with Apple’s ecosystem is that it is based on the Obj-C runtime (including Swift). It’s hard to say whether this is still necessary as it does provide a bit of an impediment for adopting any new language.

However, if there was going to be a language where someone has the expertise of already interacting with the Obj-C runtime it would be Mojo/Lattner. But given Lattner’s priorities with ML I doubt adding Obj-C runtime support would be a priority. Also Mojo isn’t yet mature and it would take time to add Obj-C runtime support. If Apple were to sponsor this project, at any time they could pull the plug and just be a big distraction for Mojo. So I think Mojo would need to become a mature ML/systems language first before any effort would go into supporting it as a first class language in the Apple ecosystem, which could be at least 5 years away?

Nonetheless, Mojo seems like a great candidate that satisfies a lot of my requirements above. Additionally, any weaknesses in Python could also be addressed in Mojo because it is a superset and won’t be as held back by Python’s existing syntax (apart from backwards compatibility).

An interesting thought with Mojo is that it could one day become a universal language used for low level systems programming and high level programming.

Some thoughts on Chris Lattner

Who am I to comment on Chris Lattner? The man is a programming genius who has made some of the greatest contributions to the field. Nonetheless some observations.

Lattner decided to effectively rewrite GCC producing LLVM. The architecture was new, yet it is effectively as a GCC compatible replacement. Then he decided to write his own C compiler: Clang. Initially it was completely standards compliant, but when he realised not one standard library was actually standards compliant he made it GCC compatible.

This shows a certain pragmatism. Lattner isn’t trying to force some new revolutionary way of doing things. It is more of an engineer and perhaps architect approach of sticking with the status quo of doing things, but just making sure it is built better behind the scenes.

Changes to Objective-C were evolutionary. Swift was more radical but bent over backwards to be compatible with both Objective-C (it requires it), C, and later Python! Also it could be argued that Swift’s syntax was a kind of portmanteau of popular languages at the time and still overwhelmingly had the “safe” C-style syntax. Nonetheless Swift was fairly revolutionary at the time even from a syntax perspective, and Lattner might have even been surprised Apple was willing to adopt it. But as I’ve mentioned in this article Swift actually feels kind of conservative as far as languages go.

Now Lattner is working on a Python compiler. So once again pragmatism reigns, it’s not a new language, a large amount of effort is based on compatibility with the existing Python ecosystem.

This all makes sense but it does give you a picture of Lattner’s strengths. It is to be compatible with the existing, but provide some magic behind the scenes with genius engineering and architecture.

Lattner isn’t going to pull a rabbit out of the hat like Ruby which completely breaks the mould. And I think he enjoys the challenge of ensuring whatever new thing he works on goes to extreme lengths to ensure existing compatibility.

I think generally speaking that is a good thing. Although there could be some exceptions. For example some experimental languages like Roc, Gleam, and Unison, are quite interesting and we will likely never see projects like that from Lattner (which is fine).

--

--