Result Builders and throws

Hello, I would like throw error when the format data is incorrect. But I don't know how to throw error outside the builder closure at init

import Foundation

struct DateFormatError: Error {}

struct Day {
    let event: String
    let date: Date
    init(event: String, textDate: String) throws {
        self.event = event
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "dd.MM.yyyy"
        guard let date = dateFormatter.date(from: textDate) else { throw DateFormatError() }
        self.date = Calendar.current.startOfDay(for: date)
    }
}
struct Week {
    let days: [Day]
    init(@WeekBuilder _ builder: () -> [Day]) { // how to make that initialiser 'throws' ?
        self.days = builder()
    }
}

@resultBuilder
struct WeekBuilder {
    static func buildBlock(_ components: (date: String, event: String)...) throws -> [Day] {
        
        let array = try components.map { try Day(event: $0.date, textDate: $0.event) }
        return array
        
    }
    
}

And how to use that? Because now I have compiler error

// Using
struct WeekTest {
    func test() {
        do {
            let week = try Week { // Error: Call can throw, but it is not marked with 'try' and the error is not handled
                (date: "12.11.2022", event: "one")
                (date: "13.11.2022", event: "two")
            }
        } catch { //'catch' block is unreachable because no errors are thrown in 'do' block
            
        }
        
    }
}

I did not find any mention of throws in the proposal

1 Like

Hi,
I came across the same problem when writing a Builder for Graphs
The best solution I've found is to rely on an intermediate Structure created by the Builder containing
both the correct components and the descriptions of the errors
Errors are not thrown by the Builder but rather in the init function using this builder results.
See Code below (Unfortunately, as new User, I cannot put all the images for the full playground ...)

1 Like

One workaround is to wrap the throwing calls into Result {} and unwrap at the result builder usage site.
An example definition can be seen here: https://github.com/apple/swift-certificates/blob/98e0f854574882d68add42640bc170161a87ddb4/Sources/X509/ExtensionsBuilder.swift#L44-L48
and the usage here:
https://github.com/apple/swift-certificates/blob/98e0f854574882d68add42640bc170161a87ddb4/Sources/X509/Extensions.swift#L133-L136

1 Like