Bird
Raised Fist0
Swiftprogramming~15 mins

BuildOptional and buildEither in Swift - Deep Dive

Choose your learning style10 modes available
Overview - BuildOptional and buildEither
What is it?
BuildOptional and buildEither are special helper functions used in Swift's result builders. They help Swift understand how to handle optional and conditional code inside a builder block. BuildOptional deals with optional values, while buildEither handles conditional branches like if-else statements. These functions let you write clean, readable code that can include optional or conditional parts inside a custom builder.
Why it matters
Without BuildOptional and buildEither, Swift's result builders wouldn't know how to process optional or conditional code inside their blocks. This would make writing flexible and readable DSLs (Domain Specific Languages) or UI code much harder. These helpers let developers write natural Swift code with ifs and optionals inside builders, improving code clarity and reducing bugs.
Where it fits
Before learning BuildOptional and buildEither, you should understand Swift basics, functions, optionals, and conditional statements. You also need to know what result builders are and how they work. After mastering these helpers, you can build complex DSLs, custom UI frameworks, or advanced Swift macros that handle optional and conditional logic smoothly.
Mental Model
Core Idea
BuildOptional and buildEither tell Swift how to include optional and conditional pieces inside a result builder, so the builder can combine them correctly.
Think of it like...
Imagine you are making a sandwich with optional ingredients and choices. BuildOptional is like deciding whether to add an optional topping or skip it, while buildEither is like choosing between two different sauces depending on your mood.
ResultBuilder Block
╔════════════════════════╗
║  ┌───────────────┐     ║
║  │ Optional part │ <-- buildOptional handles this
║  └───────────────┘     ║
║  ┌───────────────┐     ║
║  │ Conditional   │ <-- buildEither handles this
║  │ (if / else)   │     ║
║  └───────────────┘     ║
╚════════════════════════╝
Build-Up - 6 Steps
1
FoundationUnderstanding Result Builders
🤔
Concept: Introduce what result builders are and how they let you write special blocks that build complex values.
Result builders let you write code blocks that look like normal Swift code but actually create complex data structures or UI elements. For example, SwiftUI uses result builders to build views from simple code blocks.
Result
You can write cleaner, more readable code that builds complex things step-by-step.
Understanding result builders is essential because BuildOptional and buildEither only make sense inside these special blocks.
2
FoundationBasics of Optionals and Conditionals
🤔
Concept: Review how optionals and if-else statements work in Swift.
Optionals represent values that might be missing, written as Optional or Type?. If statements let you choose between code paths. These are common in Swift and appear inside result builders too.
Result
You know how to write optional values and conditional code in Swift.
Knowing optionals and conditionals helps you understand why special handling is needed inside result builders.
3
IntermediateRole of BuildOptional in Result Builders
🤔Before reading on: do you think BuildOptional simply ignores nil values or does it transform them somehow? Commit to your answer.
Concept: BuildOptional tells the builder how to handle optional values inside the block, including when the value is nil.
When you write optional code inside a result builder, buildOptional is called with the optional value. If the value is nil, buildOptional decides how to represent that absence in the final built result, often by returning an empty or default value.
Result
Optional parts inside the builder are correctly included or skipped based on their presence.
Understanding buildOptional prevents confusion about why optional code sometimes disappears or causes errors inside builders.
4
IntermediateRole of BuildEither in Conditional Branches
🤔Before reading on: do you think BuildEither handles both if and else branches the same way or differently? Commit to your answer.
Concept: BuildEither handles conditional branches by wrapping the chosen branch so the builder knows which path was taken.
When you write if-else inside a result builder, buildEither is called with either the first or second branch. It wraps the chosen branch in a special enum to keep track of which path was selected, so the builder can combine results correctly.
Result
Conditional code inside the builder works as expected, with the correct branch included.
Knowing buildEither's role helps you debug why some branches appear or disappear in builder output.
5
AdvancedCustomizing BuildOptional and BuildEither
🤔Before reading on: do you think you can customize BuildOptional and BuildEither behavior in your own result builders? Commit to your answer.
Concept: You can define your own versions of buildOptional and buildEither to control how optionals and conditionals behave in your custom builders.
By implementing static methods named buildOptional and buildEither in your result builder type, you control how optional and conditional parts are combined. For example, you might choose to skip nils or provide default values, or handle branches differently.
Result
Your custom builder handles optionals and conditionals exactly how you want.
Customizing these methods unlocks powerful control over builder behavior beyond the default.
6
ExpertInternal Mechanics of BuildOptional and BuildEither
🤔Before reading on: do you think BuildOptional and BuildEither are called once or multiple times during builder execution? Commit to your answer.
Concept: buildOptional and buildEither are called multiple times during the builder's evaluation to wrap each optional or conditional piece, enabling the builder to combine them step-by-step.
When Swift compiles a result builder block, it transforms the code into calls to buildBlock, buildOptional, and buildEither as needed. Each optional or conditional expression is wrapped by these calls, which produce intermediate values that the builder combines. This process happens recursively and allows complex nested logic.
Result
You understand how Swift transforms your builder code under the hood.
Knowing the multiple calls and wrapping explains why complex nested optionals and conditionals still work smoothly.
Under the Hood
Swift's compiler rewrites result builder blocks into a series of calls to static methods like buildBlock, buildOptional, and buildEither. For optionals, buildOptional wraps the optional value, returning a representation that the builder can combine or skip if nil. For conditionals, buildEither wraps the chosen branch in an enum (Left or Right) to track which path was taken. These wrapped values are then combined step-by-step to produce the final result.
Why designed this way?
This design lets Swift keep the builder syntax clean and natural, while the compiler handles the complexity of optionals and conditionals. Using buildOptional and buildEither as hooks allows custom builders to control how these cases behave, making the system flexible and extensible. Alternatives like forcing explicit handling in user code would be verbose and error-prone.
Result Builder Compilation Flow
╔════════════════════════════════════════╗
║ Source code with optionals and ifs     ║
║  inside builder block                  ║
╚════════════════════════════════════════╝
           │
           ▼
╔════════════════════════════════════════╗
║ Compiler transforms code into calls:   ║
║ buildBlock(...), buildOptional(...),   ║
║ buildEither(first: ...), buildEither(second: ...) ║
╚════════════════════════════════════════╝
           │
           ▼
╔════════════════════════════════════════╗
║ Builder combines wrapped values step-by-step ║
║ to produce final result                   ║
╚════════════════════════════════════════╝
Myth Busters - 4 Common Misconceptions
Quick: Does buildOptional remove nil values completely or represent them in some way? Commit to yes or no.
Common Belief:BuildOptional just removes nil optionals from the builder output silently.
Tap to reveal reality
Reality:buildOptional wraps the optional value and lets the builder decide how to handle nil, often by returning an empty or default value, not just removing it silently.
Why it matters:Assuming nils are removed silently can cause confusion when optional parts unexpectedly disappear or cause errors.
Quick: Does buildEither treat if and else branches identically or differently? Commit to your answer.
Common Belief:BuildEither treats both branches the same way without distinguishing which was chosen.
Tap to reveal reality
Reality:buildEither wraps the chosen branch in a Left or Right enum case to track which path was taken, so the builder knows exactly which branch to include.
Why it matters:Not knowing this can lead to misunderstanding why only one branch appears in output and how to customize behavior.
Quick: Can you use buildOptional and buildEither outside of result builders? Commit to yes or no.
Common Belief:BuildOptional and buildEither can be used anywhere in Swift code as normal functions.
Tap to reveal reality
Reality:They are special static methods called only by the compiler during result builder code transformation, not normal functions you call directly.
Why it matters:Trying to call them directly leads to errors and confusion about their purpose.
Quick: Does customizing buildOptional always improve builder behavior? Commit to yes or no.
Common Belief:Customizing buildOptional always makes your builder better and more flexible.
Tap to reveal reality
Reality:Customizing buildOptional can introduce subtle bugs if you don't handle nils correctly or break expected behavior.
Why it matters:Misusing customization can cause unexpected results or crashes in production.
Expert Zone
1
buildOptional and buildEither are called multiple times for nested optionals and conditionals, requiring careful recursive handling in custom builders.
2
The enum wrapping in buildEither allows pattern matching inside the builder, enabling advanced conditional logic beyond simple if-else.
3
Custom implementations of buildOptional can provide default values or logging, but must preserve builder invariants to avoid subtle bugs.
When NOT to use
Avoid using buildOptional and buildEither outside of result builders; for normal Swift code, handle optionals and conditionals directly. If your builder logic is simple and does not require optional or conditional handling, you might omit these methods. For complex asynchronous or error-handling flows, consider using async/await or Result types instead.
Production Patterns
In SwiftUI, buildOptional and buildEither are used internally to handle optional views and conditional view branches. Custom DSLs use these methods to provide flexible syntax for optional or conditional content. Advanced macros or code generators rely on customizing these methods to control code generation paths.
Connections
Monads in Functional Programming
buildOptional and buildEither behave like monadic operations that handle optional and conditional values in a computation chain.
Understanding these helpers as monads clarifies how they manage presence/absence and branching in a composable way.
Compiler Macros and Code Transformation
buildOptional and buildEither are compiler-inserted calls during code transformation of result builders.
Knowing this connection helps understand how high-level syntax maps to lower-level function calls.
Decision Trees in AI
buildEither's wrapping of conditional branches resembles decision nodes in a decision tree, choosing one path among many.
This analogy shows how conditional logic is encoded and tracked systematically.
Common Pitfalls
#1Ignoring nil optionals inside a builder causes unexpected missing output.
Wrong approach:static func buildOptional(_ component: Component?) -> Component { return component! }
Correct approach:static func buildOptional(_ component: Component?) -> Component { if let value = component { return value } else { return Component.empty } }
Root cause:Forcing unwrap without handling nil causes runtime crashes and breaks builder logic.
#2Treating buildEither branches identically loses track of which branch was chosen.
Wrong approach:static func buildEither(first component: Component) -> Component { return component } static func buildEither(second component: Component) -> Component { return component }
Correct approach:enum Either { case first(Component) case second(Component) } static func buildEither(first component: Component) -> Either { return .first(component) } static func buildEither(second component: Component) -> Either { return .second(component) }
Root cause:Not wrapping branches in distinct cases prevents the builder from distinguishing paths.
#3Calling buildOptional or buildEither directly in normal Swift code.
Wrong approach:let result = MyBuilder.buildOptional(optionalValue)
Correct approach:Use optional and conditional code inside @MyBuilder blocks; do not call buildOptional or buildEither directly.
Root cause:These methods are compiler hooks, not normal API functions.
Key Takeaways
buildOptional and buildEither are special compiler hooks that let Swift result builders handle optional and conditional code naturally.
buildOptional wraps optional values so the builder can include or skip them safely, preventing errors from nil values.
buildEither wraps conditional branches to track which path was chosen, enabling correct combination of if-else logic.
Customizing these methods in your own builders gives you powerful control over how optional and conditional parts behave.
Understanding their internal mechanics helps you write more robust, flexible, and debuggable builder-based code.

Practice

(1/5)
1. What is the main purpose of buildOptional in Swift's result builders?
easy
A. To choose between two code paths explicitly
B. To wrap optional code blocks so they can be included or skipped
C. To force unwrap optionals in code blocks
D. To create loops inside result builders

Solution

  1. Step 1: Understand buildOptional's role

    buildOptional is designed to handle optional code blocks, allowing them to be included if present or skipped if nil.
  2. Step 2: Compare with other builder functions

    buildEither chooses between two paths, but buildOptional specifically wraps optional code, making it flexible for optional UI parts.
  3. Final Answer:

    To wrap optional code blocks so they can be included or skipped -> Option B
  4. Quick Check:

    buildOptional wraps optionals = B [OK]
Hint: Remember: buildOptional handles optionals, buildEither picks sides [OK]
Common Mistakes:
  • Confusing buildOptional with buildEither
  • Thinking buildOptional forces unwrapping
  • Assuming buildOptional creates loops
2. Which of the following is the correct syntax to use buildEither for choosing the first branch in a Swift result builder?
easy
A. buildEither(option: 1) { Text("First") }
B. buildEither(second: { Text("First") })
C. buildEither(first: { Text("First") })
D. buildEither(branch: .first, content: { Text("First") })

Solution

  1. Step 1: Recall buildEither syntax

    The correct syntax uses named parameters first or second to specify the branch.
  2. Step 2: Identify the correct usage

    buildEither(first: { Text("First") }) uses buildEither(first: { ... }), which matches the official Swift syntax for choosing the first branch.
  3. Final Answer:

    buildEither(first: { Text("First") }) -> Option C
  4. Quick Check:

    buildEither first branch = A [OK]
Hint: Use named parameters first or second with buildEither [OK]
Common Mistakes:
  • Using incorrect parameter names like option or branch
  • Confusing first and second parameters
  • Trying to pass branch as enum instead of named argument
3. What will be the output of this Swift code using buildEither?
enum ResultBuilder {
  static func buildEither(first: String) -> String { "First: \(first)" }
  static func buildEither(second: String) -> String { "Second: \(second)" }
}

let result = ResultBuilder.buildEither(first: "Hello")
print(result)
medium
A. Compilation error
B. Second: Hello
C. Hello
D. First: Hello

Solution

  1. Step 1: Identify which buildEither is called

    The code calls buildEither(first: "Hello"), so the first overload is used.
  2. Step 2: Understand the returned string

    The first overload returns the string "First: Hello" which is printed.
  3. Final Answer:

    First: Hello -> Option D
  4. Quick Check:

    buildEither first branch returns "First: Hello" = A [OK]
Hint: Check which named parameter is used: first or second [OK]
Common Mistakes:
  • Assuming second branch runs when first is called
  • Expecting just the input string without prefix
  • Thinking this causes a compile error
4. Given this Swift code snippet, what is the error and how to fix it?
struct Builder {
  @resultBuilder
  struct MyBuilder {
    static func buildEither(first: String) -> String { first }
    static func buildEither(second: String) -> String { second }
  }
}

let value = Builder.MyBuilder.buildEither(third: "Oops")
medium
A. Error: No 'third' parameter; fix by using 'first' or 'second'
B. Error: Missing return statement; fix by adding return
C. Error: buildEither cannot be static; remove static keyword
D. No error; code runs fine

Solution

  1. Step 1: Identify the method call

    The code calls buildEither(third: "Oops"), but only first and second parameters exist.
  2. Step 2: Understand the fix

    To fix, replace third with either first or second to match the defined overloads.
  3. Final Answer:

    Error: No 'third' parameter; fix by using 'first' or 'second' -> Option A
  4. Quick Check:

    buildEither only accepts first or second = C [OK]
Hint: Use only first or second parameters with buildEither [OK]
Common Mistakes:
  • Trying to add unsupported parameter names
  • Ignoring static keyword requirements
  • Assuming code runs without error
5. How can you use buildOptional and buildEither together to conditionally build a SwiftUI view that shows "Logged In" if a user is logged in, "Guest" if not logged in but guest mode is enabled, and nothing otherwise?
hard
A. Use buildOptional to wrap guest mode view, and buildEither to choose between logged in and guest
B. Use buildEither to wrap guest mode view, and buildOptional to choose between logged in and guest
C. Use only buildOptional for all conditions
D. Use only buildEither for all conditions

Solution

  1. Step 1: Understand the conditions

    We have three cases: logged in, guest mode, and neither. buildEither can choose between logged in and guest mode views.
  2. Step 2: Use buildOptional for the third case

    The third case (neither) means no view, so wrap the guest mode view in buildOptional to include it only if guest mode is enabled.
  3. Step 3: Combine both builders

    Use buildEither to select logged in or guest mode, and buildOptional to skip guest mode if disabled, resulting in no view if neither condition is true.
  4. Final Answer:

    Use buildOptional to wrap guest mode view, and buildEither to choose between logged in and guest -> Option A
  5. Quick Check:

    buildOptional wraps optional guest, buildEither picks logged in or guest = D [OK]
Hint: buildEither picks branches; buildOptional skips optional parts [OK]
Common Mistakes:
  • Using buildEither alone for optional skipping
  • Using buildOptional alone for branching
  • Not handling the 'no view' case properly
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard