What are we supposed to do if a result builder goes wrong?

All the example builders I’ve seen can take all combinations of build pieces. But what if that’s not the case? If I’m building a Dictionary, I’d want to flag when someone tries a key twice. I have seen no kind of error handling in example builders (besides the structural ones imposed by your builder’s syntax).

Because of how result builders are implemented (static methods whose only input are user expressions) they're stateless, so "remembering" the components (keys) you've seen before is tougher. What you can control, though, are the inputs and outputs of the various static func build... methods.

One option might be to add a validation step before your result builder's final result can be used:

struct ValidatedResult { }

struct UnvalidatedResult {

    func validated() throws -> ValidatedResult { ... }

}

@resultBuilder struct MyBuilder {

    static func buildFinalResult(_ component: ...) -> UnvalidatedResult { ... }

}

let unvalidated = // some builder-made result
let validated = try unvalidated.validated() // throws if invalid

If you prefer, you could also use Swift's built-in Result for this purpose.

Either way, as things stand if you want to keep track of state it has to be done externally to the result builder and passed in, either via components or builder outputs.

One thing that would be nice to see happen eventually at minimum is result builders be given the ability to throw from builder methods, such that you wouldn't need to maintain an intermediate, invalid result:

@resultBuilder struct MyBuilder {

    static func buildFinalResult(_ component: ...) throws -> Result { ... }

}

@MyBuilder func build() throws { ... }

try build() // throws if build fails
1 Like