Result Builder — what it is, syntax and usage

Author: IT Sectr Published: 2026-06-20 Reading time: 8 min

Result Builder is a Swift attribute implemented via the @resultBuilder protocol that transforms a sequence of expressions into a composite value. The compiler converts code blocks with control flow constructs if, for, switch into calls to static builder methods — buildBlock, buildEither, buildArray. According to the Swift Evolution proposal SE-0289 (2022), result builders allow creating declarative DSLs inside Swift without external parsers. The most famous example is @ViewBuilder in SwiftUI, where the view body is constructed from conditional and iterative elements in a declarative style.

Key Takeaways

  • Result Builder — a Swift attribute that transforms a sequence of expressions into a resulting value through static builder methods
  • @ViewBuilder — the most famous example: it transforms multiple views into a single composite TupleView
  • Control flow constructs — the builder supports if/else, switch, for-in via buildOptional, buildEither, buildArray methods
  • Custom builders can be created for your own DSLs — HTML, CSS, configuration, queries
  • Swift 5.4 extended result builder support to functions and function parameters — now you can apply a builder to a closure argument

What is Result Builder?

Result Builder (formerly known as function builders) is a Swift mechanism that allows turning a sequence of expressions separated by line breaks into a single value. It is declared using the @resultBuilder attribute applied to a structure that implements static transformation methods.

Before result builders, the declarative syntax of SwiftUI body was impossible. Instead of a compact list of views, developers would have to write TupleView calls manually. Result Builder automatically wraps each expression, supports branching and loops, hiding the complexity of composition from the developer.

According to Swift Evolution SE-0289, accepted in 2022, the result builder is an evolution of the function builders idea (SE-0258, Swift 5.1). Key changes: renaming from @_functionBuilder to @resultBuilder and extension to function parameters, allowing builders to be used for any closure arguments, not just view bodies.

Use result builders when you need to provide users of your library with a declarative syntax for building complex structures — configurations, queries, UI components — without writing imperative assembly code.

How Result Builder Works

The Swift compiler transforms each code block marked with @resultBuilder into a sequence of calls to static builder methods. Let’s look at a simple builder that concatenates strings:

swift
@resultBuilder
struct StringBuilder {
    static func buildBlock(_ parts: String...) -> String {
        parts.joined(separator: " ")
    }
}

Using this builder — each string on a separate line is concatenated with a space:

swift
@StringBuilder
func greeting() -> String {
    "Hello"
    "World"
    "from"
    "Swift"
}
// Compiler transforms this into:
// StringBuilder.buildBlock("Hello", "World", "from", "Swift")
// Result: "Hello World from Swift"

The compiler groups consecutive expressions and passes them as variadic parameters to buildBlock. If an if appears between expressions, the compiler calls buildOptional or buildEither for branching. For for-in loops it calls buildArray. Thus, regular Swift code is transformed into a chain of calls that construct the final value.

Builder Methods: buildBlock, buildOptional, buildEither

Each result builder defines a set of static methods that the compiler calls during transformation. The main methods:

MethodPurposeWhen Called
buildBlockCombines a sequence of expressionsFor each block without branching
buildOptionalHandles if without elseWhen if appears without else
buildEither(first:)First branch of if-elseFor if with else
buildEither(second:)Second branch of if-elseFor if with else
buildArrayHandles for-in loopsWhen for-in is present
buildExpressionTransforms individual expressionsFor each expression before passing to buildBlock
buildFinalResultFinal transformationBefore returning from the closure

A minimal implementation requires only buildBlock with variadic parameters — this is sufficient for blocks without branching. Adding buildOptional and buildEither enables support for conditional constructs, and buildArray enables loops. According to Swift Documentation (2025), it is recommended to implement all methods for maximum DSL flexibility.

buildExpression allows accepting expressions of different types and converting them to a single builder type. For example, in @ViewBuilder, buildExpression accepts Text, Image, Button and converts them to the common View type.

Creating a Custom Result Builder

Let’s look at creating a builder for constructing HTML strings. This DSL will allow writing declarative HTML directly in Swift:

swift
@resultBuilder
enum HTMLBuilder {
    static func buildBlock(_ components: String...) -> String {
        components.joined()
    }

    static func buildOptional(_ component: String?) -> String {
        component ?? ""
    }

    static func buildEither(first component: String) -> String {
        component
    }

    static func buildEither(second component: String) -> String {
        component
    }

    static func buildArray(_ components: [String]) -> String {
        components.joined()
    }
}

Using the custom builder to generate HTML:

swift
func div(@HTMLBuilder _ content: () -> String) -> String {
    "<div>\(content())</div>"
}

func p(_ text: String) -> String {
    "<p>\(text)</p>"
}

let page = div {
    p("Hello")
    p("World")

    if showFooter {
        p("Footer")
    }
}
// Result: <div><p>Hello</p><p>World</p><p>Footer</p></div>

According to the article “Building Custom Result Builders in Swift” from Swift.org (2025), custom builders are used in libraries for building configuration files, UI components, data mapping, and even database queries — anywhere where a declarative syntax with branching support is needed.

@ViewBuilder in SwiftUI

@ViewBuilder is a result builder built into SwiftUI that is applied to the content parameter of most container views: VStack, HStack, ZStack, Group, List, and the body property itself. It allows writing multiple views on separate lines without commas or wrappers.

@ViewBuilder implements all result builder methods, including support for if-else, switch, and for-in. When a condition is true, buildEither(first:) returns one view; when false, buildEither(second:) returns another. Both branches must return the same type, but SwiftUI uses AnyView internally or type erasure through ConditionalContent.

swift
struct GreetingView: View {
    let isLoggedIn: Bool

    var body: some View {
        VStack {
            Image(systemName: "person.circle")
            Text("Profile")
                .font(.title)

            if isLoggedIn {
                Text("Welcome back!")
                    .foregroundColor(.green)
            } else {
                Button("Log In") { }
            }
        }
    }
}

Without @ViewBuilder, the same code would require Group for each conditional section or using AnyView, which hurts performance. @ViewBuilder automatically selects the most efficient representation — ConditionalContent or TupleView — for each combination.

Limitations of Result Builder

The first limitation is the maximum number of expressions in buildBlock. The Swift standard library defines buildBlock overloads for 2–10 expressions. If a block has more than 10 expressions, the compiler will produce an error. The solution is grouping via Group or VStack to split into sub-blocks.

The second limitation is the lack of support for variables and assignments inside the builder block. You cannot declare let x = 5 inside @ViewBuilder. All expressions must be expressions returning a value of the builder type. For intermediate calculations, use computations outside the builder or buildExpression with support for different types.

The third limitation is debugging complexity. Compilation errors inside a result builder often produce confusing messages, especially when types mismatch in if/else branches. Use explicit return types and AnyView for debugging, though the latter reduces performance. According to Hacking with Swift (2025), a practical tip is to start with a simple builder without branching and gradually add conditional construct support.

Frequently Asked Questions

What is Result Builder in Swift?

Result Builder is a Swift attribute that transforms a sequence of expressions into a resulting value through static methods. It allows creating declarative DSLs, the most famous example being @ViewBuilder in SwiftUI for building view hierarchies without imperative code.

How do I create my own Result Builder?

Declare a structure with the @resultBuilder attribute and implement at least the buildBlock method. To support conditions, add buildOptional and buildEither; for loops, add buildArray. Use the builder attribute before the closure parameter in a function.

Which methods are mandatory for Result Builder?

Only buildBlock is mandatory. All other methods — buildOptional, buildEither, buildArray, buildExpression, buildFinalResult — are optional and add support for corresponding constructs. The more methods implemented, the more flexible the DSL.

Why is @ViewBuilder a Result Builder?

@ViewBuilder is a concrete implementation of the result builder for the View protocol. It is defined in SwiftUI as a structure with the @resultBuilder attribute, providing buildBlock methods for different numbers of views (TupleView), buildEither for ConditionalContent, and buildArray for ForEach.

Is there a limit on the number of expressions in a builder?

Yes, the standard buildBlock overloads support up to 10 expressions. When exceeding this, use nested containers (Group, VStack) to split into sub-blocks. A custom builder can define a variadic buildBlock without limitation.

Summary

  • Result Builder — a Swift attribute that transforms a sequence of expressions into a single value through static builder methods
  • The compiler replaces a code block with calls to buildBlock, buildEither, buildOptional, buildArray depending on control flow constructs
  • @ViewBuilder — SwiftUI’s built-in result builder that allows writing declarative view hierarchy code with support for conditions and loops
  • Custom builders are used for building DSLs: HTML, configurations, queries — any structure that benefits from declarative syntax
  • Limitations: max 10 expressions in buildBlock, cannot declare variables, confusing compilation errors when types mismatch
  • Swift 5.4+ — builders can be applied to function parameters, expanding use cases beyond view bodies

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also