# Function builders

**URL:** <https://forums.swift.org/t/function-builders/25167>\
**Category:** Pitches\
**Created:** [June 3, 2019, 10:11pm UTC](https://forums.swift.org/t/function-builders/25167 "2019-06-03T22:11:10Z")\
**Posts on this page:** 5\
**Page:** 20

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [April 23, 2020, 4:26am UTC](https://forums.swift.org/t/function-builders/25167/384 "2020-04-23T04:26:26Z")

</div>

I run into exact same problem here:

- [Is this a function builder bug or is my builder incorrect?](https://forums.swift.org/t/is-this-a-function-builder-bug-or-is-my-builder-incorrect/35144)
- (incomplete function builder) [swift-legacy-user-interface/LayoutBuilder.swift at master · UndefinedAlgorithm/swift-legacy-user-interface · GitHub](https://github.com/UndefinedAlgorithm/swift-legacy-user-interface/blob/master/Sources/Layout/Core/LayoutBuilder.swift#L1)
- (workaround overload 🙁) [swift-legacy-user-interface/HStackLayout.swift at master · UndefinedAlgorithm/swift-legacy-user-interface · GitHub](https://github.com/UndefinedAlgorithm/swift-legacy-user-interface/blob/master/Sources/Layout/Layouts/HStackLayout.swift#L20-L29)

I pinged @Douglas_Gregor on twitter in that regard, but have not received any answer yet.

---

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [April 23, 2020, 4:51am UTC](https://forums.swift.org/t/function-builders/25167/385 "2020-04-23T04:51:08Z")

</div>

As I [replied on Twitter](https://twitter.com/dgregor79/status/1252312204558229509?s=20), this is a bug that has been fixed on master but did not make it into Xcode 11.4. It's also specifically called out in the thread on [function builders implementation progress](https://forums.swift.org/t/function-builders-implementation-progress/32981).

Doug

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [April 23, 2020, 4:53am UTC](https://forums.swift.org/t/function-builders/25167/386 "2020-04-23T04:53:04Z")

</div>

Argh, dang it, twitter bugged out on me, I didn't get any notifications that you replied. Sorry about that. ☹

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [April 23, 2020, 5:03am UTC](https://forums.swift.org/t/function-builders/25167/387 "2020-04-23T05:03:14Z")

</div>

@Douglas_Gregor one question.

Does `buildExpression` have to return the same type as `buildBlock`?

For some reason I couldn't make my function builder work otherwise. Ideally I want `buildExpression` to only wrap the expression into some type eraser / container ((`buildExpression(_: Expression) -> AnyLayout`) and then `buildBlock` to pick it up and return an array `buildBlock(_: AnyLayout...) -> [AnyLayout]`). Right now I used the `HTML` example from the original draft to workaround the problem.

```swift
@_functionBuilder
public enum LayoutBuilder {
  typealias Component<Content> = [AnyLayout<Content>]
  
  // FIXME: Can we just return `AnyLayout<T.Content>` here?
  static func buildExpression<T>(
    _ expression: T
  ) -> [AnyLayout<T.Content>] where T: Layout {
    [expression.wrapIntoAnyLayout()]
  }

  // FIXME: Can this just be `(AnyLayout<Content>) -> AnyLayout<Content>`? 
  static func buildIf<Content>(
    _ children: Component<Content>?
  ) -> Component<Content> {
    children ?? []
  }

  // FIXME: Can we remove this? Why is this one even needed? 
  static func buildBlock<Content>(
    _ component: Component<Content>
  ) -> Component<Content> {
    component
  }

  // FIXME: Ideally we want the parameter to be `AnyLayout<Content>...`
  // and the return type `[AnyLayout<Content>]`
  static func buildBlock<Content>(
    _ children: Component<Content>...
  ) -> Component<Content> {
    // FIXME: Use `.flatMap(\.self)` when compiler bug is resolved.
    children.flatMap { $0 }
  }
}

```

Ideally something like should be enough:

```swift
@_functionBuilder
public enum LayoutBuilder {
  static func buildExpression<T>(
    _ expression: T
  ) -> AnyLayout<T.Content> where T: Layout {
    expression.wrapIntoAnyLayout()
  }

  static func buildIf<T>(
    _ child: T?
  ) -> AnyLayout<Content> where T: Layout {
    child.wrapIntoAnyLayout()
  }

  static func buildBlock<Content>(
    _ children: AnyLayout<Content>...
  ) -> [AnyLayout<Content>] {
    children
  }
}

```

---

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [April 23, 2020, 5:33am UTC](https://forums.swift.org/t/function-builders/25167/388 "2020-04-23T05:33:58Z")

</div>

> [@DevAndArtist](#):
>
> Does `buildExpression` have to return the same type as `buildBlock` ?

No, but the definitions you have for `buildBlock` require that every `buildExpression` call must produce the _same_ type, because `Component<Content>...` takes a homogeneously-typed set of arguments. Hence, you need to type-erase somewhere or you need to have N overloads of `buildBlock` to account for 0..\<N input expressions.

Doug

[Previous page](https://forums.swift.org/t/function-builders/25167.md?page=19)
