How Result Builders and Opaque Return Types Make SwiftUI Possible
The line var body: some View is likely the most-written line in SwiftUI. We have a sense of the purpose it serves, but likely don’t stop to examine the Swift language features that make it possible. Examining the usage of result builders and opaque return types in detail helps illuminate SwiftUI's identity and diffing behavior, and gives a clearer understanding of those language features themselves.
Structural Identity in SwiftUI
Because views are values and not objects — views are descriptions of UI, not instances of it — SwiftUI needs to be able to efficiently compare them to determine when to update the view tree. Unlike frameworks such as React, which primarily reconcile UI structure at runtime using a virtual DOM, SwiftUI pushes much more structural information into the type system at compile time. Achieving this requires a mechanism capable of assigning concrete static types to deeply nested hierarchies containing different view types and control flow such as if statements.
SwiftUI heavily relies on structural identity — the position and static type information of views in the hierarchy — to determine how updates should be applied efficiently. This means that erasing the type to something like AnyView removes structural type information SwiftUI could otherwise use during diffing and update propagation. It would also force SwiftUI to rely more heavily on dynamic dispatch.
Encoding View Hierarchies with @ViewBuilder
SwiftUI’s solution for encoding the structure of a view is to use a result builder. The content closure of each SwiftUI view is implicitly annotated with one: @ViewBuilder. It transforms the body into a concrete nested generic type at compile time. Let’s look at a simple view definition as an example.
struct ExampleView: View {
var showImage: Bool
var body: some View {
HStack {
Text("Hello")
if showImage {
Image(systemName: "star")
} else {
Text("World")
}
Button("Tap me") { }
}
}
}The compiler relies on @ViewBuilder to desugar it to look roughly like this.
ViewBuilder.buildBlock(
Text("Hello"),
ViewBuilder.buildEither(
first: Image(systemName: "star")
),
Button("Tap me") { }
)The else branch would similarly use buildEither(second:).
That yields this fully specified type.
HStack<TupleView<(Text, _ConditionalContent<Image, Text>, Button<Text>)>>You can see how beautifully this fits into SwiftUI’s declarative style; the type itself is a compile-time map of the hierarchy — every branch of control flow and every container is encoded structurally.
Hiding Complexity with Opaque Return Types
This is only half of the solution, though. If every view were exposed as a highly nested generic type, every place a view was referenced would need to include its fully specified type and cascading updates would be needed for simple changes to a single view in a hierarchy. This would create a very brittle structure. Swift addresses this with another language feature: opaque return types. Opaque return types are sometimes described as the opposite of generics because instead of the caller choosing the type, the implementation chooses it. This lets the type be hidden to callers — hence the word “opaque”. The compiler knows the full concrete type, while callers only know that it conforms to the View protocol.
The Takeaway
SwiftUI’s design works because these features complement each other perfectly: @ViewBuilder preserves the complete structural shape of the hierarchy for the framework and compiler, while some View hides that complexity from API boundaries. The result is a system that remains declarative and ergonomic while still retaining compile-time knowledge about the UI tree. It’s impressive how much complexity this design shifts into the compiler and type system. Understanding that flow gives a much clearer picture of SwiftUI’s architecture and many of its behavioral nuances.


Another interesting corollary is equality. Views can actually conform to Equatable. This lets SwiftUI compare them using only the important fields you specify to possibly avoid unnecessary updates. So it's the answer to “if this is the same conceptual view, are the new inputs equivalent enough that SwiftUI can skip updating it?”