# Result builder expressiveness and type inference

**URL:** <https://forums.swift.org/t/result-builder-expressiveness-and-type-inference/56417>\
**Category:** Discussion\
**Tags:** result-builder\
**Created:** [March 31, 2022, 7:10pm UTC](https://forums.swift.org/t/result-builder-expressiveness-and-type-inference/56417 "2022-03-31T19:10:41Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![stephencelis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/stephencelis/32/2675_2.png) [@stephencelis](https://forums.swift.org/u/stephencelis)\
**Post date:** [March 31, 2022, 7:10pm UTC](https://forums.swift.org/t/result-builder-expressiveness-and-type-inference/56417/1 "2022-03-31T19:10:41Z")

</div>

Result builders are designed to be expressive, and also performant, but this second requirement can sometimes impact the first. As brought up previously on the forums:

> [@Function builder cannot infer generic parameters even though direct call to \`buildBlock\` can](https://forums.swift.org/t/function-builder-cannot-infer-generic-parameters-even-though-direct-call-to-buildblock-can/35886):
>
> Hi folks, I got a question about a function builder diagnostic. Our deep learning library defines a Sequential type for sequentially composing neural network layers. It's powered by a function builder called LayerBuilder. Sequential is used like this: let model = Sequential { Conv2D\<Float\>(...) // first layer, feeding output to: AvgPool2D\<Float\>(...) // second layer, feeding output to... Flatten\<Float\>() Dense\<Float\>(...) Dense\<Float\>(...) } And ideally, we'd like the fu…

This thread does a great job explaining the design of one-way constraints, and why this generic must be specified on each line and is not inferred. The thread also suggests a workaround:

> [@Function builder cannot infer generic parameters even though direct call to \`buildBlock\` can](https://forums.swift.org/t/function-builder-cannot-infer-generic-parameters-even-though-direct-call-to-buildblock-can/35886/23):
>
> This isn't quite what I was getting at. Since (IIRC) builder types can be generic, you can write something like this: protocol Transformation { associatedtype Value func transform(values: [Value]) -\> [Value] } @\_functionBuilder struct TransformationBuilder\<Value\> { static func buildExpression\<T: Transformation\>(t: T) -\> AnyTransformation\<Value\> where T.Value == Value { ... } static func buildBlock(transforms: AnyTransformation\<Value\>) -\> AnyTransformation\<Value\> { ... } } func makeT…

But in practice, this does not seem to work as soon as you nest builders (a common thing to do!). To take the thread's example further, parameterization can allow this to build just fine:

```swift
@LayerBuilder<Float>
let model = Sequential { // ✅ Inference works great, and quickly!
  Conv2D(...)
  AvgPool2D(...)
  Flatten()
  Dense(...)
  Dense(...)
}

```

But `Float` is not propagated to any nested builders:

```swift
@LayerBuilder<Float>
let model = Sequential {
  Sequential {
    Conv2D(...) // 🛑 Inference is broken here, and slow :(
    AvgPool2D(...)
    Flatten()
    Dense(...)
    Dense(...)
  }
}

```

My hope would be that the desugared builder would look something like this:

```swift
let e0 = LayerBuilder<Float>.buildExpression(
  // `buildExpression` is constrained so that `Sequential`'s `LayerBuilder`
  // must be generic over `Float`:
  Sequential {
    let e0 = LayerBuilder<Float>.buildExpression(Conv2D(...))
    let e1 = LayerBuilder<Float>.buildExpression(AvgPool2D(...))
    let e2 = LayerBuilder<Float>.buildExpression(Flatten())
    let e3 = LayerBuilder<Float>.buildExpression(Dense(...))
    let e4 = LayerBuilder<Float>.buildExpression(Dense(...))
    let e5 = LayerBuilder<Float>.buildBlock(e0, e1, e2, e3, e4)
    return e5
  }
)

```

But despite the constraint on `buildExpression`, the inner `LayerBuilder` is not properly constrained.

Is this a bug or simply a limitation of the design of result builders?

---

<div class="post-metadata">

**Author:** ![stephencelis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/stephencelis/32/2675_2.png) [@stephencelis](https://forums.swift.org/u/stephencelis)\
**Post date:** [April 1, 2022, 3:14pm UTC](https://forums.swift.org/t/result-builder-expressiveness-and-type-inference/56417/2 "2022-04-01T15:14:37Z")

</div>

@Douglas_Gregor Since you worked on the one-way constraints I was curious if you could weigh in on this limitation? Is it something that could be fixed?
