resultBuilder: are overloads of buildBlock allowed/encouraged when needed?

I am having trouble following the documentation on resulBuilder. It doesn't seem to mention that one is allowed to overload the methods, e.g., buildBlock yet the compiler allows it. Toy example:

struct Foo {}

@resultBuilder enum SumBuilder {
  static func buildBlock(_ f: Foo, _ components: Int...) -> Int {
    2 * components.reduce(0) { a, b in a + b }

  static func buildBlock(_ components: String...) -> Int {
    components.reduce(0) { a, b in a + b.count }

  static func buildBlock(_ components: Int...) -> Int {
    components.reduce(0) { a, b in a + b }

@SumBuilder var x: Int {
print(x)  // outputs 9

@SumBuilder var y: Int {
print(y)  // outputs 11

struct X {
  @SumBuilder var s: Int {
print(X().s)  // outputs 20

So is the only thing that matters the name, buildBlock? From the example, looks like most anything flies parameter-wise.

What am I missing/doing wrong here? Or is this totally fine and it's just that the documentation makes no mention of it?

1 Like

What you probably want is buildExpression, overloading of which allows you to specify how different types can be automatically converted into a standard one for the purpose of your result builder. These can, for example, convert various numeric formats to Int or take the count of a String or something. Your buildBlock will then be called with the result of those buildExpression calls, allowing you to keep the buildBlock implementation clean.

Thanks, and yes, I am aware of buildExpression and able to use it. To clarify, I did not have any issues defining the builder. My question was about the fact that the documentation (the language reference on attributes) does not mention the ability to overload buildBlock whereas the compiler accepts many such overloads I've thrown at it. I guess this is just an omission and overloads of buildBlock are acceptable but I wanted to hear an authoritative opinion, if anyone knows for sure.

I think the documentation doesn't specify that because of the fundamental way result builders work: they're (as far as I know) a purely syntactic replacement of bare expression statements with relevant result builder method names with no prior type checking. This means that the result builder behaves identically to hand-written code that calls builder functions with the respective names. So, any overload resolution, any type inference, anything else the type checker may do will happen as normal.

1 Like