Roadmap for Improving the Swift Type Checker
This is all, of course, about the dreaded
the compiler is unable to type-check this expression in reasonable timeerror. This error can appear with both valid and invalid code, and the various workarounds are unsatisfactory, to say the least. Splitting up an expression into smaller pieces, introducing type annotations, or attempting other refactorings will sometimes allow valid code to type check, or in the invalid case, surface an actionable diagnostic. However, this breaks flow and becomes a frustrating process of trial and error “shotgun debugging” even for the most experienced Swift programmers. The compiler doesn’t even tell you if your expression is valid or not![…]
For a more detailed overview of constraint solving in the Swift type checker, see swift/docs/TypeChecker.md at main · swiftlang/swift · GitHub. For an explanation of why overload resolution is inherently hard, and why every known approach has exponential running time in the worst case, see How does compiler compile SwiftUI code? - #4 by Slava_Pestov and Lambda Expressions vs. Anonymous Methods, Part Five | Microsoft Learn.
[…]
The main goal then, is to devise sufficiently-general heuristics which can quickly solve most realistic problem instances, without hard-coding too many special cases, so that hopefully, the exponential running time only appears with pathological examples which are unlikely to occur in practice. The primary way to accomplish this is to attempt disjunction choices in the right order---this includes both choosing the next disjunction to attempt, and the next choice within a disjunction to attempt. Also, we can avoid considering disjunction choices that lead to contradictions. By doing this, we can find the valid solutions more quickly, and spend less time exploring long “dead ends.”
A secondary goal is to improve the auxiliary data structures and algorithms used in the constraint solver, so that even if an exhaustive search must be attempted on a given expression, as will sometimes be the case, we burn less CPU time while considering the same search space.
I’m glad to see that this is being taken seriously and that they’re also considering minor source-breaking changes that could produce big benefits.
Previously:
- Swift 6.2: Approachable Concurrency
- Swift 6.2
- Rewriting the TypeScript Compiler in Go
- Swift at 10
- Compiling Swift Generics
- Swift Type Checking Is Undecidable
- Swift 5.3 Released
- Playing Jenga With Swift’s Type Checker
- The Secret Life of Types in Swift
- Exponential Time Complexity in the Swift Type Checker
- Speeding Up Slow Swift Build Times
- Swift Type-checking Performance Case Study
- Slow Swift Array Type Inference
30 Comments RSS · Twitter · Mastodon
> This is all, of course, about the dreaded the compiler is unable to type-check this expression in reasonable time error. This error can appear with both valid and invalid code, and the various workarounds are unsatisfactory, to say the least. Splitting up an expression into smaller pieces, introducing type annotations, or attempting other refactorings will sometimes allow valid code to type check, or in the invalid case, surface an actionable diagnostic. However, this breaks flow and becomes a frustrating process of trial and error “shotgun debugging” even for the most experienced Swift programmers
If the compiler times out on valid code because it can’t type check in a reasonable amount of time doesn’t that simply mean they bit off more than they can chew? The system seems broken, or at least very flawed at a core level. These computer scientist nerds should have known this from the beginning and designed the language to require the developer to write the type then. I dk I live in ObjC world but even absurdly long type names fill in code completion after typing like 3 or 4 characters.
Maybe I’m crazy. Apple is introducing bugs all over the place and I’m spinning my fucking wheels on every macOS update writing workarounds, swizzling methods, doing all kinds of voodoo while they are just fucking geeking out on a whiteboard solving problems that they themselves created and shoving SwiftUI trash underneath everything. Touching code they should keep their filthy hands off of. Just fing go back to Objective-C and swallow your pride. Ohh safety ohh give me safety….
—-
I just read a few comments on Hacker News…here is a good one:
“As someone who started doing SwiftUI recently, it absolutely boggles my mind that (1) this is even a thing and (2) Apple seem ok to treat it as an unsolvable problem. When you finally solve it is some stupid wrong type passed in somewhere. I agree with the other poster. This is so pathetic it makes me question the competence of the engineers working on Swift.
Smells like “we made a poor architectural / design choice and ain’t walking it back”.“
Did all the Objc ppl at Apple retire or did Steve Jobs keep these guys in line
Slava links to a Microsoft blog post about C# 3.0.
However, he forgot to quote the most important bit in that blog post:
> Does this really matter in practice? As I mentioned last time, hopefully not. Other languages also have this issue. When I ran an early draft of this post past him, Erik Meijer immeditely pointed out that the ML type inference system has similar worst cases, and the Haskell type inference system is even worse. Apparently in Haskell you can encode a Turing machine into the type system and make the compiler run it! In practice these sorts of problems do not arise in real-world code in any of these languages, so I am not too worried about it for C# 3.0.
And indeed, in practice, you never hit these issues. If you do, you are likely aware of the problem in the first place and know how to break the code to work around it.
Contrast with Swift, specifically some of the most mundane SwiftUI examples, and you hit issues very, very quickly. This was a known issue at the time of framework design, and some PM still pushed this garbage before the compiler was sufficiently improved.
Looking at all the increasing usage of Rust in Linux, FreeBSD, Ubuntu userland, browsers and everywhere else, mostly for safety, what would it be like if Apple adopted that as well instead?
I dk I’ve never written any Rust.
But the cost of type inference is clearly substantial and so obviously not worth it. Even for classes like NSCollectionViewCompositionalLayout I can type NSCo and code completion fills the rest. This juice ain’t worth the squeeze and they are chasing an inferior programming crowd that obsesses over dumb things like square brackets. Apple used to set the bar.
The entire SwiftUI things came about because Apple started chasing quantity over quality. They want to lure the React Native JavaScript crowd and those types of programmers like to just write var but at the same time you got these compiler people shoveling in tons of keywords increasing complexity and safety is a must so the types must be checked. It’s bestiality. C++ has auto but c++ is slow to compile too (in comparison to ObjC but maybe not as slow as Swift)
ObjC was the 3rd most popular programming language in the world before. Swift has never ranked anywhere close to that. It is ironic and kind of sad.
@Objc4life Objective-C is fine without type inference, but types in Swift are so unwieldy that it would be really unpleasant without it.
@Michael "it would be really unpleasant without it."
Considering that, if we exaggerate a little, that every line of Swift code is already 70% keyword ornaments and 30% mostly obfuscated real code, would it really make a difference to remove type inference and just have to write the type?
The Rust compiler *is* slow compared to languages that prioritize compiler speed or have had much more time to optimize for compilation time. It is getting faster, though, and there are already ways you can improve compilation time, like picking a faster linker. If Apple were to use Rust as their primary programming language, I'd assume that they would invest in improving compilation time and would make progress relatively quickly.
Having said that, I don't think Rust would be a good choice. In hindsight, Google was smart to just pick Java for Android. Java isn't anyone's first choice, but it's competent and unopinionated, which is what you want if you're basically forcing tons of different people to standardize on the same programming language. It also allowed Google to switch to Kotlin and introduce actually useful features, like null safety, without completely upsetting their community.
(Also, type inference is, in my opinion, an anti-feature in a programming language, since it makes the programmer's intention less obvious for future readers of one's code.)
@Plume Why would you assume that Apple would invest in rust compiler? The Swift compiler is their own, for a language they own, and look at how bad that is.
Regarding type inference, the ship has sailed. You can’t have SwiftUI as it was designed without it. SwiftUI sits on a foundation of lies, tears and generic type slop that can’t really be typed (some of the generic types are hidden types).
Even C++ added some type inference to the language due to template slop. It’s just not ergonomic to type any of the slop, while creating type-erased types introduces performance overhead (e.g. std::function vs direct lambda call) and leads to a similar result.
When they make UIKit/AppKit wrap SwiftUI instead of the other way around they are forcing everyone to eat the fruit of the poisoned tree.
> Regarding type inference, the ship has sailed.
To get the ship back on the right track, for the good of the platform (Mac especially) the way forward should be to quietly enforce the following rules internally:
1. SwiftUI should never be the base. SwiftUI must remain a thin wrapper over AppKit/UIKit.
2) Develop new APIs exclusively in Objective-C. This doesn’t need to be explicitly advertised just little wink wink is good enough.
3) Stop lying to the developer community and insulting everyone’s intelligence with ridiculous statements like “the best way to write an app is with Swift and SwiftUI.”
4) Work on ObjecticeC 3.0 quietly and release it in three years. Learn from the mistakes of Swift. I’m talking a real ObjectiveC improvement/successor not a bastard child of C++.
5) Transfer Josh Schaffer to Siberia, he can perhaps manage the Apple Store there. He should get a coat and bring that fucking Wayne Gretzky puck with him. Maybe he can play fetch with his dog with it on the frozen lakes.
This of course would take courage.
Is there a tool that compiles a Swift program and adds the inferred types into the source code? The next compile cycle should be faster.
Anyway, this article reminded me of a HN thread where I complained about this problem and Chris Lattner and Slava Pestov both joined to discuss it: https://news.ycombinator.com/item?id=45137960
@TillEnd That ship, too, has sailed. NSButton in 26.0 is a wrapper around SwiftUI. The whole glass implementation is a Swift+SwiftUI wrapper. UIToolbar is now a SwiftUI wrapper. Etc.
@Léo I believe you. Is there concrete evidence of this that I can check & refer others to? Also, is it already happening in both AppKit and UIKit? To what extent, what about UICollectionView and other complex views?
@Tom Yes, the engineers have talked about it, and it’s obvious if you look at process samples or crash logs.
Another tool to see evidence of this is using the view hierarchy inspector in Xcode and looking at the private hierarchies of various Apple views, like the ones I mentioned above.
>(Also, type inference is, in my opinion, an anti-feature in a programming language, since it makes the programmer's intention less obvious for future readers of one's code.)
@Plume Yes lots more "Jump to Definition" what's that... when you are looking at code you didn't write.
> @TillEnd NSButton in 26.0 is a wrapper around SwiftUI. The whole glass implementation is a Swift+SwiftUI wrapper. UIToolbar is now a SwiftUI wrapper. Etc.
Yea I know this but it could quite easily be reversed and walked back. It sounds far-fetched and I guess it is but only because it has basically become a self-fulfilling prophecy. The developer community never gave Apple proper pushback on Swift (and still isn't). So here we are. To not fall down the seemingly inevitable Swift pit of disaster of course would require the people in charge to think rationally and not emotionally --admit that this is all causing harm and walk it back.
From the blog post:
> Optimized disjunction selection
>Recent main development snapshots introduced a large set of changes that @xedin has been working on for several years now, to improve disjunction selection, by collecting more information to decide what disjunction should be attempted next. Unlike the targeted optimizations in Swift 6.2 which offered incremental wins without reducing the fundamental complexity of the problem, the disjunction selection changes allow the type checker to quickly solve many expressions that we were formerly unable to type-check. The new algorithm can also drastically speed up expressions that would type check, but were just under the limit and thus slow.
The more I think about this the more infuriating this all is. Swift is 10 years old? Spending years to "solve"...type checking? All that effort and all these resources are going in that...and assuming they "solve it" (improve it really so it isn't as bad is basically the stated goal)...what is really gained here? It's a superficial feature. Where's the effort to fix all the bugs? The awful layout of System Settings, etc. If SwiftUI is so flexible and portable cross platform why do SwiftUI apps so often disable window resizing or limit it to a single dimension?
Perhaps some improvements will lessen the pain for current Swift developers but this has been years and type checking isn't the only problem when it comes to Swift. There is plenty of other pain Swift developers get elsewhere... I think most of them have a high tolerance for it.
That said, a language designed for app development should be focused on productivity gains for app developers. It should not be designed for the developers of the compiler to give themselves brain teasers (my language is so magical you don't have to WRITE THE TYPE!). It's like they are solving a Rubik's cube for their own personal glory and ego. But what does this all do for apps and app developers? Nothing, really. To program properly you are required to know your types so design your language to make them write the type then type checking is a breeze. Then you are free to focus on features that could actually be useful. You don't need a computer science degree from Stanford to figure that out. The more time they spend trying to *fix* Swift the worse it seems to get.
You gotta stop the bleeding somewhere. The rational way to proceed would be to keep Objective-C as the core language. Allow current Swift devs can just call in to Objective-C like they always have. Think about all the mistakes you made, what language features are really worth implementing from the perspective of APP development productivity first and use the lessons learned from the Swift disaster to do better in ObjC 3.0.
> Is there a tool that compiles a Swift program and adds the inferred types into the source code?
The tool would basically have to do type inference and infer the type to put it in the source code so it'd be the same thing? And If there was/is, the existence of such a tool basically proves that the programming language was designed poorly.
In an alternate universe, Apple had simply kept improving objective-c and none of us would be wasting any time even thinking about such fundamental things. Imagine about all the wonderful things we could have had if they had actually delivered “objective c without the c.” Maybe working LLM services in Siri, for example.
In an alternate universe, Apple had kept alive the cocoa java bridge and we’d at least have an escape hatch, cause frankly at this point, even Java seems like it’d have been a better option.
Have to second @objc, the bleeding needs to stop. They designed themselves into a tower, they’ll have to roll back at some point, the sooner the less painful it will be.
The issue is that ObjC champions in the company left one by one. Instead, came the bored type “theorist” compiler bros who had no interest in improving a boring to them language; people who never developed a UI software in their life and had no idea what works for UI and what makes it different from system programming. They also probably sold Swift as a corporate-friendly language that will nanny even the juniorest of juniors (aka cheap) engineering. And the nuts took over the nuthouse. You see glimmers of the nuthouse when a current zealot argues with a disillusioned one in the HN discussion linked above by Tom. Lattner, suddenly designing a language with a very specific usecase and target audience in mind, finds that the type theorist masterpiece is an impractical mess. (Not to say Mojo is suitable for UI-oriented programming either.)
The “ObjC without the C” slogan is likely marketing looking for a way to sell it initially, as we know from the start there was no intention to have such a thing as “ObjC without the C“. Swiftfluencers took over quickly is the main marketing/brainwashing machine, as they saw a gold rush opportunity.
I personally think that a “Swift Lite” subset of Swift that’s super fast to compile at the expense of losing a bit of syntax sugar and convenience is long overdue - and I would switch to it (plus real time previews, or actually hot reloading) much more gladly than to whatever today’s flavor of Swift 6.x async is.
@ObjC4Life I find that most of the time these compiler assisted features like jumping to definition or showing the inferred type don’t even work in Swift. It’s been like this since the beginning.
@Léo It’s not just Obj-C, though. It seems like they’ve even gotten bored with the older parts of Swift. It’s always on to the next new feature rather than finishing or polishing what came before. And for some reason they feel the need to rush SwiftUI, Swift Concurrency, and Swift Data out the door before they’ve been properly dogfooded.
@Léo yes the idea was that the compiler would do it in a special “make following compiles faster” mode. Or it would be that Lite mode that you would need to do this before turning it on. Something like that, a migration step sort of…
@ObjC4Life:
> The tool would basically have to do type inference and infer the type to put it in the source code so it'd be the same thing?
Yes. Except that it would either be allowed to run for longer time, or it would have better diagnostics for when it fails.
> And If there was/is, the existence of such a tool basically proves that the programming language was designed poorly.
Yes. It would. I would still use it. Or tell Codex to use it and fill in the types.
@Michael Absolutely. Every recent effort from Apple has been half-baked at best, broken at worst, be it consumer-facing, framework, API design, language design or developer tool. Just zero quality control, zero quality demand from engineering. The more passes, the more I feel Federighi is just a R&D lead. Maybe he was an excellent engineer, I do not doubt that, but the more his responsibility has grown, the more quality has tanked.
This news strikes me as both "it's about time" and also "too little, too late". For all breakage they do, this would be worth it to undo the mess caused by the Type fetishists. But with Swift, the academics always win.
The HN thread was interesting. Chris learned at least one lesson.
@Tomas Swift Lite won't happen. They have Embedded Swift and it doesn't cut nearly enough. My tactic is to dodge Swift whenever possible and use things that spark joy. When I download someone's Swift sample code "Claude rewrite this in Obj-C". Obj-C feels like a superpower. Rapid iteration, better understanding, no yearly code breakage: Timeless joy 👌🏻
@Léo Are they doing to the View layer with SwiftUI what they did to Foundation with Swift? The View layer will eventually be one giant SwiftUI slop and the traditional AppKit/UIKit controls will just float on it? That sounds gross, but they already did similar with Autolayout (another overly-complicated mistake).
@ObjC4Life They're in too deep to reverse. Even if they did, the language and team still have all the wrong influences (Rust envy, React envy, C++ envy). I don't want guys that hang out at the intersection of Design By Committee Ave and Kitchen Sink Rd having any hand in a post-Swift future.
@Hammer I don't see how that's viable currently, given the state of SwiftUI. They are just getting lazy. "Oh, I need to layout this toolbar? I'll just do it in SwiftUI and break everything on the way" (just to demonstrate how ridiculous this implementation is currently, UINavigationController.toolbar isn't even part of the view hierarchy, nor is it even sized or placed correctly for frame checking).
They are however moving some stuff to Swift, which also didn't exist before. I guess they are using the new Swift impl of an ObjC header (https://github.com/swiftlang/swift-evolution/blob/main/proposals/0436-objc-implementation.md) that they recently released. It's terrible for debugging, since Apple now insists on stripping most of their Swift code, which they do not do for ObjC. You can still find the function pointers from the ObjC runtime, but it's nowhere near as convenient, and crash backtraces aren't readable.
> just to demonstrate how ridiculous this implementation is currently, UINavigationController.toolbar isn't even part of the view hierarchy, nor is it even sized or placed correctly for frame checking).
Try flipping a UIBarButtonItem hidden from true to false (or from YES to NO if you’re Objective-C)…it doesn’t work.
> Even if they did, the language and team still have all the wrong influences (Rust envy, React envy, C++ envy). I don't want guys that hang out at the intersection of Design By Committee Ave and Kitchen Sink Rd having any hand in a post-Swift future.
I share all these concerns and perhaps there needs to be some De-Schaeffing (or is it Un-Schaeffing?) first. If they aren’t capable of learning from their mistakes pivoting to something else (ObjC 3.0) would solve nothing.
>They designed themselves into a tower, they’ll have to roll back at some point, the sooner the less painful it will be.
@ben yea…bottom is going to fall out eventually. they are still only at the beginning of the big Swift port and look how messy it is. And it seems to get worse not better over time. Or maybe ten years from now they’ll still be trying to type check those expressions in under 25 seconds but by then I’m sure most of us will be writing our code in some other language
@Objc4life @Ben
I argue the bottom has fallen out. No one controls their stack like Apple, yet they've lost most of their platform (native app) advantage.
Electron largely beat Apple on its own platforms. It's become such a default, you now have to make a case to do native dev at many companies. What's Apple's response to the Chromium menace? "Web apps don't get Liquid Glass" lol. Advantage: Electron.
Apple spent a decade doing the Swifty Dance while the platform quality dropped so hard that web apps are now "good enough" for most users. "Technically sound" Swift didn't stop Apple's own software quality largely dropping to F-tier.
Swift didn't make native dev significantly faster or easier. Devs still must exert a ton of effort to get details right (esp those Apple gets wrong). Devs are constantly on the Churn Train while the Swifties figure out "What is app dev? We made a Systems language".
Swift basically lost home field advantage to a language designed in 10 days.