Bird
Raised Fist0
Swiftprogramming~30 mins

@resultBuilder attribute in Swift - Mini Project: Build & Apply

Choose your learning style10 modes available
Building a Simple HTML Builder with @resultBuilder
📖 Scenario: Imagine you want to create HTML code using Swift in a clean and readable way. Swift's @resultBuilder attribute helps you build complex structures like HTML by writing code that looks like regular Swift code but produces HTML strings.
🎯 Goal: You will build a simple HTML builder using @resultBuilder that lets you write HTML elements in Swift code and get the final HTML string as output.
📋 What You'll Learn
Create a HTMLBuilder result builder to combine strings
Write a function buildHTML that uses @HTMLBuilder
Use the builder to create multiple HTML elements inside buildHTML
Print the final combined HTML string
💡 Why This Matters
🌍 Real World
Using <code>@resultBuilder</code> helps developers write clean and readable code for building complex data like HTML, JSON, or UI layouts.
💼 Career
Understanding <code>@resultBuilder</code> is useful for Swift developers working on SwiftUI, DSLs, or any code that benefits from declarative syntax.
Progress0 / 4 steps
1
Create the HTMLBuilder result builder
Create a struct called HTMLBuilder with the @resultBuilder attribute. Inside it, write a static function buildBlock that takes a variadic parameter of String and returns a single String by joining all parts.
Swift
Hint

Use @resultBuilder before the struct name. The buildBlock function combines all strings into one.

2
Create the buildHTML function using @HTMLBuilder
Write a function called buildHTML that uses the @HTMLBuilder attribute. The function should return a String and have no parameters. Inside the function, return multiple HTML element strings like "

Hello

"
and "

Welcome to Swift

"
on separate lines.
Swift
Hint

Use @HTMLBuilder before the function. Return multiple strings inside the function body.

3
Call buildHTML and store the result
Create a constant called html and assign it the result of calling buildHTML().
Swift
Hint

Use let html = buildHTML() to store the result.

4
Print the final HTML string
Write a print statement to display the value of the html constant.
Swift
Hint

Use print(html) to show the final HTML string.

Practice

(1/5)
1. What is the main purpose of the @resultBuilder attribute in Swift?
easy
A. To combine multiple expressions into a single result in a clean way
B. To declare a new type of variable
C. To handle errors automatically
D. To create a new thread for concurrent execution

Solution

  1. Step 1: Understand the role of @resultBuilder

    @resultBuilder is used to combine multiple code lines or expressions into one result, making code cleaner and easier to write.
  2. Step 2: Compare options with the purpose

    Options B, C, and D describe unrelated features. Only To combine multiple expressions into a single result in a clean way correctly describes the purpose of @resultBuilder.
  3. Final Answer:

    To combine multiple expressions into a single result in a clean way -> Option A
  4. Quick Check:

    @resultBuilder purpose = combine expressions [OK]
Hint: Remember: @resultBuilder combines code lines into one result [OK]
Common Mistakes:
  • Confusing @resultBuilder with error handling
  • Thinking it creates new variables
  • Assuming it manages concurrency
2. Which of the following is the correct way to declare a custom result builder in Swift?
easy
A. @resultBuilder class MyBuilder { func buildBlock(_ components: Int...) -> Int { components.reduce(0, +) } }
B. @resultBuilder struct MyBuilder { static func buildBlock(_ components: Int...) -> Int { components.reduce(0, +) } }
C. @resultBuilder func MyBuilder(_ components: Int...) -> Int { components.reduce(0, +) }
D. struct MyBuilder { func buildBlock(_ components: Int...) -> Int { components.reduce(0, +) } }

Solution

  1. Step 1: Identify correct @resultBuilder declaration

    A custom result builder must be declared as a struct or enum with the @resultBuilder attribute and static buildBlock method.
  2. Step 2: Check each option

    @resultBuilder struct MyBuilder { static func buildBlock(_ components: Int...) -> Int { components.reduce(0, +) } } correctly uses @resultBuilder on a struct and static buildBlock method. struct MyBuilder { func buildBlock(_ components: Int...) -> Int { components.reduce(0, +) } } misses @resultBuilder and static keyword. @resultBuilder func MyBuilder(_ components: Int...) -> Int { components.reduce(0, +) } wrongly applies @resultBuilder to a function. @resultBuilder class MyBuilder { func buildBlock(_ components: Int...) -> Int { components.reduce(0, +) } } uses a class, which is not allowed.
  3. Final Answer:

    @resultBuilder struct MyBuilder { static func buildBlock(_ components: Int...) -> Int { components.reduce(0, +) } } -> Option B
  4. Quick Check:

    Custom builder = struct + @resultBuilder + static buildBlock [OK]
Hint: Use @resultBuilder on struct with static buildBlock method [OK]
Common Mistakes:
  • Forgetting static keyword on buildBlock
  • Applying @resultBuilder to functions
  • Using class instead of struct or enum
3. Given the following code, what will be printed?
 @resultBuilder struct SumBuilder {
    static func buildBlock(_ components: Int...) -> Int {
        components.reduce(0, +)
    }
}

func sum(@SumBuilder _ content: () -> Int) -> Int {
    content()
}

let result = sum {
    2
    3
    5
}
print(result)
medium
A. Error: Missing return
B. 235
C. 0
D. 10

Solution

  1. Step 1: Understand buildBlock behavior

    The buildBlock method receives all integers (2, 3, 5) and sums them using reduce(0, +), resulting in 10.
  2. Step 2: Check function call and output

    The sum function calls content(), which triggers the builder and returns 10. print(result) outputs 10.
  3. Final Answer:

    10 -> Option D
  4. Quick Check:

    Sum of 2+3+5 = 10 [OK]
Hint: Sum builder adds all values inside closure [OK]
Common Mistakes:
  • Thinking values concatenate as strings
  • Expecting a syntax error
  • Missing that buildBlock returns sum
4. Identify the error in this custom result builder code:
 @resultBuilder struct MyBuilder {
    func buildBlock(_ components: String...) -> String {
        components.joined(separator: ", ")
    }
}

func buildString(@MyBuilder _ content: () -> String) -> String {
    content()
}

let result = buildString {
    "Hello"
    "World"
}
print(result)
medium
A. Missing return statement in buildBlock
B. Cannot use String type in result builder
C. buildBlock must be static
D. Function buildString should not have @MyBuilder

Solution

  1. Step 1: Check buildBlock method declaration

    In a result builder, buildBlock must be a static method. Here it is an instance method (missing static).
  2. Step 2: Verify other parts

    Return statement is present, String type is allowed, and function parameter correctly uses @MyBuilder.
  3. Final Answer:

    buildBlock must be static -> Option C
  4. Quick Check:

    buildBlock static keyword required [OK]
Hint: Always make buildBlock static in result builders [OK]
Common Mistakes:
  • Omitting static keyword on buildBlock
  • Confusing return statement presence
  • Thinking @resultBuilder restricts types
5. You want to create a custom result builder that builds a dictionary from key-value pairs written inside a closure. Which of the following implementations correctly uses @resultBuilder to achieve this?
hard
A. @resultBuilder struct DictBuilder { static func buildBlock(_ components: (String, Int)...) -> [String: Int] { var dict = [String: Int]() for (key, value) in components { dict[key] = value } return dict } } func buildDict(@DictBuilder _ content: () -> [String: Int]) -> [String: Int] { content() } let dict = buildDict { ("a", 1) ("b", 2) ("c", 3) } print(dict)
B. @resultBuilder struct DictBuilder { static func buildBlock(_ components: [String: Int]...) -> [String: Int] { components.reduce([:]) { $0.merging($1) { $1 } } } } func buildDict(@DictBuilder _ content: () -> [String: Int]) -> [String: Int] { content() } let dict = buildDict { ["a": 1] ["b": 2] ["c": 3] } print(dict)
C. @resultBuilder struct DictBuilder { static func buildBlock(_ components: String...) -> [String: Int] { [:] } } func buildDict(@DictBuilder _ content: () -> [String: Int]) -> [String: Int] { content() } let dict = buildDict { "a:1" "b:2" "c:3" } print(dict)
D. struct DictBuilder { static func buildBlock(_ components: (String, Int)...) -> [String: Int] { var dict = [String: Int]() for (key, value) in components { dict[key] = value } return dict } } func buildDict(@DictBuilder _ content: () -> [String: Int]) -> [String: Int] { content() } let dict = buildDict { ("a", 1) ("b", 2) ("c", 3) } print(dict)

Solution

  1. Step 1: Check for @resultBuilder attribute and static buildBlock

    @resultBuilder struct DictBuilder { static func buildBlock(_ components: (String, Int)...) -> [String: Int] { var dict = [String: Int]() for (key, value) in components { dict[key] = value } return dict } } func buildDict(@DictBuilder _ content: () -> [String: Int]) -> [String: Int] { content() } let dict = buildDict { ("a", 1) ("b", 2) ("c", 3) } print(dict) correctly declares @resultBuilder on a struct and has a static buildBlock method that combines tuples into a dictionary.
  2. Step 2: Verify code correctness and usage

    @resultBuilder struct DictBuilder { static func buildBlock(_ components: [String: Int]...) -> [String: Int] { components.reduce([:]) { $0.merging($1) { $1 } } } } func buildDict(@DictBuilder _ content: () -> [String: Int]) -> [String: Int] { content() } let dict = buildDict { ["a": 1] ["b": 2] ["c": 3] } print(dict) uses arrays of dictionaries which works but is less direct than tuples; @resultBuilder struct DictBuilder { static func buildBlock(_ components: String...) -> [String: Int] { [:] } } func buildDict(@DictBuilder _ content: () -> [String: Int]) -> [String: Int] { content() } let dict = buildDict { "a:1" "b:2" "c:3" } print(dict) returns empty dictionary ignoring input; struct DictBuilder { static func buildBlock(_ components: (String, Int)...) -> [String: Int] { var dict = [String: Int]() for (key, value) in components { dict[key] = value } return dict } } func buildDict(@DictBuilder _ content: () -> [String: Int]) -> [String: Int] { content() } let dict = buildDict { ("a", 1) ("b", 2) ("c", 3) } print(dict) misses @resultBuilder attribute, so it won't work as a builder.
  3. Final Answer:

    Option A correctly implements a dictionary builder using @resultBuilder -> Option A
  4. Quick Check:

    @resultBuilder + static buildBlock + tuple input = correct dictionary builder [OK]
Hint: Use tuples and static buildBlock with @resultBuilder for dictionary [OK]
Common Mistakes:
  • Forgetting @resultBuilder attribute
  • Returning empty or wrong type
  • Using non-static buildBlock
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