it's that the fundamental design of SwiftUI
Is it SwiftUI, or resultBuilder?
it's that the fundamental design of SwiftUI
Is it SwiftUI, or resultBuilder?
the number of overloads is one of the biggest problems.
e.g.Group.init(content:)has 11 overloads andForEach.init(_:content:)has 14 overloadswhich IIUC all (or most?) need to be considered.
But not all of these have equal probability, right? Could the compiler weight overloads by the frequency with which it encounters them and then use those weights to more intelligently try the most probable paths?
Almost like an LLM. Have the compiler learn which paths are 12-lane superhighways and which ones are tiny little footpaths. Potentially across all codebases that it compiles?
Boy, identifying the problem(s) is a huge win, and a great starting point for alternatives.
Tooling and best practices often compensate for gaps in semantics and compilers, once the gaps are identified.
Scope of the problem: Are there other disjunctions besides overloads? Or other sources of speculative ambiguity?
Detection: How hard would it be to make a swift-lint warn on excessive overloads? (That's probably a lot more relevant the LOC in a file or method)
Best-practice workaround: taking the Group.init(..) example, could users not build their own static factory extensions to avoid the ambiguities (makeTab(...), makeScene(..))? Then one might (make tools to automagically) migrate to the less ambiguous API's.
In order to have determinism in overload selection, as well as not be inundated with âambiguous use of ___â errors, the compiler has a series of hierarchical rules it uses to determine whether a given overload is âbetterâ than another overload. For instance, if you have one function f that takes an Int and another that takes Any, then f(0) will always call the first one because it is in some sense a âbetter matchâ than picking the Any-taking version. While this makes avoiding frustrating ambiguities easier, it also means that finding some solution to an expression cannot be the end of the compilerâs work, because if thereâs other overloads available that havenât been explored yet then there might be another solution out there which just hasnât been found. Which is to say, even if you can make intelligent guesses about where the most likely solution is, that doesnât save you from having to explore all possible options.
Of course, finding the best solution early does help you in some ways because it means you can potentially stop exploring other branches earlierâas soon as their âscoreâ dips below the score of the best solution so far you donât have to bother with them anymore, because whether or not you found a solution on that branch you wouldnât pick it!
This is actually a major difference between Swiftâs constraint solver, and SAT solvers. Iâm not at all familiar with the state of the art in SAT solving these days, but at least in the classical formulation, youâre just asked to produce some satisfying assignment of your variables, if one exists; describing all solutions is a harder problem.
I just solved a bad diagnostic problem in a student's code that I had to post here ![]()
struct SwiftUIView: View {
var body: some View {
List {
Section {
} header: {
Text("Header")
} footer: {
("Footer")
}
}
.toolbar { // â Ambiguous use of 'toolbar(content:)'
ToolbarItem(placement: .confirmationAction) {
}
}
}
}
I would find this very persuasive if the errors produced were of decent quality, but the errors I run into are usually reports like
@autoclosure parameter, replace () with ()" (which doesn't do anything)I could go on but how about at least fixing those four first?
This seems like the obvious solution to me. So much of this problem is because developers don't have a clear sense of when they are making the type checker work too hard.
There's no need to "break the world" - just introduce warnings whenever the type checker is being forced to do anything heroic (regardless of how long it actually takes) with a fixit to insert an explicit type.
Existing code will still work, and by fixing the warnings we can cut compile times and avoid the catastrophic type-checker failures ever arising.
Is this something swiftformat could achieve in the meantime or it is something we cannot reasonably ask such a tool to attempt to do?
It's unclear if you mean swiftformat or swift-format (
) but in either case I think the answer is probably "no". SwiftFormat (both of them) operate at a simple syntactic level, treating each file in isolation - they have no idea of the types of any of the symbols you are using, nor any way to gather that information unless they happen to be declared in the same file.
It is theoretically possible to augment either tool with an additional processing pass that gathers all the files in your project and does symbol resolution and type analysis on them, but at that point you'd have just recreated the Swift compiler (aka SourceKit).
SwiftLint actually uses SourceKit under the hood for some of its rules, so maybe it would be possible to write a SwiftLint rule for this? You'd need to be quite familiar with the workings of the type system to know which specific code arrangements to flag though.
If the preceding discussion is to be taken at face value, wouldn't that be...essentially any use of SwiftUI? (It would certainly be any use of an infix arithmetic operator with literal operands.)
That would be enough, though, to flag every use of import SwiftUI with a warning, "don't." ![]()
Sometimes I feel like replying to this thread and other times I don't. I feel like I don't for a few reasons. First, I want to avoid appearing as arrogant. I have no solutions. Type checking is obviously a challenging problem and if there were ways the compiler could make these easily reproducible problems go away I'm confident there would at least be plan communicated for it. Second, I'm sure the problem is compounded by using certain APIs like SwiftUI and the Composable Architecture that dispose programmers to writing code a certain way that takes advantage of many Swift features which lean heavily on the type system.
But there are times I feel like I should reply to this thread. I have to deal with "unable to type-check this expression in reasonable time" multiple times a day, commenting out blocks of code and waiting for it compile only to find it was something as dumb as missing optional chaining because my memory of the type's properties is not clear and code completion has stalled.
Wearied, today I want to say: I love Swift and I'm hurting here. Is there anything I can reasonably do to help?
And for what it's worth, I would gladly accept the pain of a one-off source breaking change than repeatedly hurt into the future. I think most of us here are developers for Apple platforms, so we're used to changes breaking things ![]()
Overall, I have about 3 different project of significant size that I got to the point in SwiftUI composition that I had a typo or something involving type misuse, and the compiler just gave up telling me nothing about where the error was. I completely gave up on one because I needed to make significant type and system construction changes and if I didn't do those one small piece at a time, I would spend hours commenting and uncommenting code trying to figure out what was broken.
I just find this to indicate a rather immature group of developers with a rather poor architecture system, it it's really this fragile. I make deliberate choices now days to just not start anything else while all these gyrations are on going. It's truly sad, because I am going to estimate that more than 50% of people trying out swift will reach such a point and give up.
In my workplace's projects it's so bad that everything gives up. The compiler doesn't even report diagnostics it just freezes or crashes without any message. SourceKit is dead, nothing works from there. Xcode gives up and both diagnostics and the source code editor become unresponsive.
I end up spending some time fixing those typos in TextEdit because at least it doesn't freeze everything.
To be fair it is a large legacy project (C/C++/Objective-C++/OpenGL/Metal/Swift 1-2-3-4-5/Kotlin) with incremental builds of around 5-15 minutes.
Help is on the way: Xcode 26 Beta's Coding Assistant found & fixed this bug with ease.
More help on the way: Xcode 26 Beta's Coding Assistant solves this issue nicely.
Before:
let address = "127.0.0.1"
let username = "steve"
let password = "1234"
let channel = 11
let url = "http://" + username
+ ":" + password
+ "@" + address
+ "/api/" + channel
+ "/picture"
print(url)
After:
let address = "127.0.0.1"
let username = "steve"
let password = "1234"
let channel = 11
let channelString = String(channel)
let credentials = username + ":" + password
let url = "http://" + credentials + "@" + address + "/api/" + channelString + "/picture"
print(url)
Hilariously, Xcode 26 Beta 2 seems to have gotten worse. If I set a deployment target to macOS 26+, the type-checker all of a sudden times out while checking a complex Predicate. But if I change the deployment target back to macOS 14.6+, it works just fine.
I give up, man. In another 20 years we'll all just talk to AIs and they'll write binary directly. We won't need programming languages. I guess that'll solve the type-checker.
This usually happens when additional overloads are added which increase the number of possible solutions. A big improvement was recently merged but we won't see it until Swift 6.3. It doesn't help now, but you could try toolchains from main to see if things improve.
That would make me extremely sad, both for the state of the world's software and because I genuinely enjoy writing code.
Personally, I'm strictly against handicapping the language to please the slow working Type Checker. I believe there's large untapped optimisation potential in its implementation, technically and algorithmically.
And yes, I run into compiler timeouts daily, working with SwiftUI. Usually I find quick workarounds, like quickly scanning for syntax highlighting (because the syntax highlighter actually shows a typo right away!) before starting to comment out blocks of code. One good thing this experience taught me is to move out all logic from the view body into separate functions.