SE-0289 (review #2): Result Builders

To give a serious review: I don't like the name "result builders" at all. As others have mentioned, it is so non-specific that it really doesn't help anybody understand what it does. The older name "function builders" also wasn't very descriptive, but at least it wasn't so bland and nebulous.

As I mentioned in the previous review, I see these things as a kind of heterogeneous list-builder. So you start with an Array literal:

let x = [
  1,
  2,
  3
]

These elements all have to have the same type. So what if we wanted to build a heterogeneous list? Well, we'd need generic parameters for each element of the list:

let x = [
  1,
  "two",
  3.0
] // would have to be something like List<Int, String, Double>

Or in SwiftUI terms, a TupleView<X, Y, Z>. There are all kinds of use-cases for these heterogeneous lists across the language; one that springs to mind is the TensorFlow team's automatic requirement satisfaction idea: Automatic Requirement Satisfaction in plain Swift. The structural representations from that pitch (copied below to save you all a click) are analogous to SwiftUI's View hierarchies and could be written using a function-builder DSL instead of a cons-list:

// before:
return StructuralStruct(Point.self,
                StructuralCons(StructuralProperty("x", x, isMutable: true),
                    StructuralCons(StructuralProperty("y", y, isMutable: true),
                        StructuralEmpty())))
// maybe? with a builder...
return Struct(Point.self) {
  \.x
  \.y
} // -> Struct<WriteableKeyPath<Point, Double>, WriteableKeyPath<Point, Double>>

This feature also takes it a step further by allowing some limited control-flow, if the list you are trying to build has types to represent things like conditional content. Conditionals can get kind of confusing, but that's the way I find works best for me: to consider the conditional content as always being in the list (it is always part of the resulting type, for instance), albeit in a wrapper to mark that it's conditional and perhaps should be ignored.

let x = [
  1,
  if someCondition {
    "two"
  },
  3.0
] // -> List<Int, Conditional<String>, Double> 

I don't really think it makes sense to call this a "result builder" or a "function builder". I consider it a "list builder", and if I ever find it difficult to understand some SwiftUI code, I usually ask myself "what is the list that I'm building? what is its type? what are its elements?", and that tends to help me straighten out any issues.

I think the way you approach this feature has a big impact on what you think the naming should be. I think @listBuilder or some variant of that would work well, and the builder function names could perhaps be tweaked to focus more on the task of building a list, rather than trying to look like a syntax transformation without properly exposing the AST.

2 Likes