# 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:** 20\
**Page:** 14

<div class="post-metadata">

**Author:** ![kansaichris](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kansaichris/32/2703_2.png) [@kansaichris](https://forums.swift.org/u/kansaichris)\
**Post date:** [June 11, 2019, 11:13pm UTC](https://forums.swift.org/t/function-builders/25167/262 "2019-06-11T23:13:55Z")

</div>

> [@John\_McCall](#):
>
> I think people are getting hung up about variadic generics because SwiftUI specifically would benefit from them, but most users don't need them; normal variadic functions are fine if you don't need type propagation.

> [@kansaichris](#):
>
> With all due respect, this feels a bit contradictory to me. As far as I understand it, the whole _raison d'être_ of this proposal—and the rejection of other alternatives like receiver closures—is SwiftUI's need for type propagation, which most users don't need, so by your logic, we shouldn't get hung up about type propagation, either, because most users don't need it.

> [@John\_McCall](#):
>
> That's a fair complaint, although I think there are other advantages to this approach beyond what receiver closures can express.

Right. To be clear, I didn't mean to focus on receiver closures or any other alternative in particular—I just found it odd that you have claimed the technique used in this proposal is absolutely necessary because it allows for type propagation, but then dismissed variadic generics because most people won't need the very same type propagation that's put forward as the reason for adopting this proposal.

---

<div class="post-metadata">

**Author:** ![jawbroken](https://avatars.discourse-cdn.com/v4/letter/j/cc9497/32.png) [@jawbroken](https://forums.swift.org/u/jawbroken)\
**Post date:** [June 12, 2019, 4:27am UTC](https://forums.swift.org/t/function-builders/25167/263 "2019-06-12T04:27:36Z")

</div>

> [@flowtoolz](#):
>
> I think the syntax should express the syntax. And the names should express the meaning. You can always encounter code that is very well named but from an unfamiliar application domain. In that case the syntax should be clear anyway.

It's not clear to me what this means. There's nothing really unusual about the syntax here, just that seemingly-ignored values in a closure are being collected in a particular way, which seems like semantics. There are plenty of places in Swift where things that are different semantically have indistinguishable syntax (e.g. calling pure versus impure functions, variables with value versus reference semantics), which can have downsides (confusion) and upsides (uniformity, concision).

---

<div class="post-metadata">

**Author:** ![cbarrett](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cbarrett/32/7007_2.png) [@cbarrett](https://forums.swift.org/u/cbarrett)\
**Post date:** [June 12, 2019, 5:13am UTC](https://forums.swift.org/t/function-builders/25167/264 "2019-06-12T05:13:03Z")

</div>

> [@Joe\_Groff](#):
>
> similar transformations ought to be possible for `switch` , `catch` , `guard` , and non-loop control flow constructs in the fullness of time

Has the scenario of a function builder building a `switch` not into an Either but into that same enum (or something isomorphic)? I think this might enable monad-like things (eg. reading or writing some implicit state) in a clean way, but I have not thought through all the details. So it also might affect other parts of the feature (buildOptional) in undesirable ways. Anyway, I would be thrilled to hear someone else had done the hard thinking here already 🙂

---

<div class="post-metadata">

**Author:** ![flowtoolz](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/flowtoolz/32/13358_2.png) [@flowtoolz](https://forums.swift.org/u/flowtoolz)\
**Post date:** [June 12, 2019, 7:05am UTC](https://forums.swift.org/t/function-builders/25167/265 "2019-06-12T07:05:28Z")

</div>

> [@jawbroken](#):
>
> It's not clear to me what this means.

It means that I believe that stripping away the naming and looking at `foo()`and `bar()` etc. is perfectly valid for making an argument about syntax and syntax readability. Also I believe that the syntax should ideally be clear without understanding the names that some programmer (maybe me a long time ago) chose. Fair enough there is sometimes a trade-off and so a balance to strike. But in contrast to function overloading and value versus reference types, this here is a rather modern/unusual/special feature for a language that is at its core object oriented and functional. Therefor Builder Functions (or however they're gonna be called) deserve to be treated as the special case and the behaviour of these "special" closures should be very explicit in my humble opinion.

---

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [June 12, 2019, 8:07am UTC](https://forums.swift.org/t/function-builders/25167/266 "2019-06-12T08:07:23Z")

</div>

In the interest of avoiding any misunderstanding, I wanted to notify the thread that we've merged the initial implementation of this feature into the Swift repository. This does not substantively affect this discussion; it was done for technical reasons and should certainly not be interpreted as an endorsement of just releasing the status quo in Swift 5.1. I believe I've already made it clear that we expect changes to the design before release. Nonetheless, since we do expect some form of this feature to make the cut, and since keeping a large PR branch in working condition has real costs (which grow as the release grows closer), we decided (with core-team approval) that it was okay to immediately integrate it in its current working state.

---

<div class="post-metadata">

**Author:** ![Tino](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tino/32/1073_2.png) [@Tino](https://forums.swift.org/u/Tino)\
**Post date:** [June 12, 2019, 9:09am UTC](https://forums.swift.org/t/function-builders/25167/267 "2019-06-12T09:09:25Z")

</div>

> [@John\_McCall](#):
>
> I think there are other advantages to this approach beyond what receiver closures can express.

If this is meant to be a real (open) discussion (rather than an announcement that function builders will be added to Swift), imho those advantages should be listed explicitly.  
As it has been mentioned many times before, this is no democracy, and it's not required to convince "the community" - but still it wouldn't hurt to get as many people on board as possible.

---

<div class="post-metadata">

**Author:** ![tali](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tali/32/11346_2.png) [@tali](https://forums.swift.org/u/tali)\
**Post date:** [June 12, 2019, 11:13am UTC](https://forums.swift.org/t/function-builders/25167/268 "2019-06-12T11:13:09Z")

</div>

How is that information used by `ConditionalContent`? Does it help in diffing Views?

---

<div class="post-metadata">

**Author:** ![Joe\_Groff](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joe_groff/32/1929_2.png) [@Joe\_Groff](https://forums.swift.org/u/Joe_Groff)\
**Post date:** [June 12, 2019, 2:16pm UTC](https://forums.swift.org/t/function-builders/25167/269 "2019-06-12T14:16:00Z")

</div>

The builder doesn't directly produce an `Either` type, it invokes `buildEither` overloads on the builder type, so your implementation has some control over how that gets reassembled into a result. It might nonetheless be inconvenient to reassemble it into your original enum, though, given John's scheme of producing a balanced binary tree of `buildEither`s to join the branches.

---

<div class="post-metadata">

**Author:** ![cbarrett](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cbarrett/32/7007_2.png) [@cbarrett](https://forums.swift.org/u/cbarrett)\
**Post date:** [June 12, 2019, 5:34pm UTC](https://forums.swift.org/t/function-builders/25167/270 "2019-06-12T17:34:38Z")

</div>

Right, I think we are following each other now, so let me go out on a limb and spell out in more detail what my line of thinking was last time:

If one is using a function builder, either to carry some data "over" the expressions and statements, such as a Reader type, or "alongside" as in the case of a Stream type like Combine, so adding complete and error cases, won't one want that Reader struct that holds the state, or that Stream enum, to be what this function builder is overloaded on, and not Either? (Or some function type involving them, anyway. Hmm.)

Anyway, thanks for your reply, maybe mine is "food for thought" for a future proposal.

---

<div class="post-metadata">

**Author:** ![djtech42](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/djtech42/32/23960_2.png) [@djtech42](https://forums.swift.org/u/djtech42)\
**Post date:** [June 12, 2019, 5:47pm UTC](https://forums.swift.org/t/function-builders/25167/271 "2019-06-12T17:47:09Z")

</div>

I can't seem to get `buildIf` working in Xcode 11. It gives a `segmentation fault (11)` for me. Is something wrong in the code here?

```
@_functionBuilder
public struct StringBuilder {
    public static func buildBlock(_ children: String...) -> String {
        return children.joined()
    }

    public static func buildIf(_ child: String?) -> String {
        return child ?? ""
    }
}

@StringBuilder
public func combinedString(spaced: Bool) -> String {
    "test"
    if spaced {
        " "
    }
    "other"
}

```

---

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [June 12, 2019, 6:03pm UTC](https://forums.swift.org/t/function-builders/25167/272 "2019-06-12T18:03:56Z")

</div>

No, that looks like it should work, and it should _definitely_ not be crashing the compiler. Mind filing a bug over at [our open-source tracker](https://bugs.swift.org)?

---

<div class="post-metadata">

**Author:** ![djtech42](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/djtech42/32/23960_2.png) [@djtech42](https://forums.swift.org/u/djtech42)\
**Post date:** [June 12, 2019, 7:07pm UTC](https://forums.swift.org/t/function-builders/25167/273 "2019-06-12T19:07:56Z")

</div>

Thanks, opened an issue (SR-10923)

---

<div class="post-metadata">

**Author:** ![rumnat](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/rumnat/32/7823_2.png) [@rumnat](https://forums.swift.org/u/rumnat)\
**Post date:** [June 14, 2019, 4:01am UTC](https://forums.swift.org/t/function-builders/25167/274 "2019-06-14T04:01:22Z")

</div>

Now we have a limit of max 10 items inside View body. The function declaration leaves something to be desired [https://developer.apple.com/documentation/swiftui/viewbuilder/3278693-buildblock](https://developer.apple.com/documentation/swiftui/viewbuilder/3278693-buildblock). Lack of variadic generics added complexity and API workaround to Combine and Function builders. I do believe all of that is going to be changed by the release.

---

<div class="post-metadata">

**Author:** ![yxckjhasdkjh](https://avatars.discourse-cdn.com/v4/letter/y/278dde/32.png) [@yxckjhasdkjh](https://forums.swift.org/u/yxckjhasdkjh)\
**Post date:** [June 14, 2019, 11:11am UTC](https://forums.swift.org/t/function-builders/25167/275 "2019-06-14T11:11:40Z")

</div>

When it was requested to allow [extensions for structural types](https://forums.swift.org/t/supporting-extensions-for-structural-types/20661), such as tuples, one of the arguments for not doing it right now was that [it would require variadic generics to do properly](https://forums.swift.org/t/supporting-extensions-for-structural-types/20661/38) and Swift doesn't want to implement a half-baked mechanism that will need to be replaced later. Even though in practice, the length of tuples that people are going to use very probably has some reasonable upper bound (who's going to use 50-element tuples?).

Now we're talking about a feature where, without variadic generics, you can only put up to 10 items inside a view body—something that is a very real limitation in practice—but the feature is merged anyway. Yes, maybe variadic generics will happen until the release. It's more likely that they are not though, and then nobody is going to rip the feature back out again.

I find this to be weirdly inconsistent and it's one of the reasons why I wrote [in the other thread](https://forums.swift.org/t/important-evolution-discussion-of-the-new-dsl-feature-behind-swiftui/25168/61) that it doesn't look as if the Swift Core team cares about the fundamental issues with Swift as much as about flashy new features that can be marketed well.

---

<div class="post-metadata">

**Author:** ![Lantua](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lantua/32/8868_2.png) [@Lantua](https://forums.swift.org/u/Lantua)\
**Post date:** [June 14, 2019, 11:44am UTC](https://forums.swift.org/t/function-builders/25167/276 "2019-06-14T11:44:23Z")

</div>

Let's not get haughty, variadic generic is a big endeavor, which I don't see it getting done soon, even as a priority.

With that said, Swift doesn't seem to shy away from doing this kind of thing (tuple equality, hashable, comparable, etc).

---

<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:** [June 14, 2019, 1:06pm UTC](https://forums.swift.org/t/function-builders/25167/277 "2019-06-14T13:06:35Z")

</div>

@John_McCall I finally could catch up the proposal and this thread. So far I'm overwhelmed by the complexity of this feature. Don't get me wrong, I like it a lot, but it was and still is hard to wrap your mind around it.

@gregtitus mentioned on Slack that the compiler executes the builder functions in a _depth-first-traversal_ way, which is not mentioned anywhere in the proposal or in this thread, but this tiny information was crucial in my learning process. Knowing this makes this feature less magical and more predictable.

Here a good example:

```swift
@_functionBuilder
struct TestBuilder {
  typealias Component = [Int]
  
  static func buildBlock(_ children: Component...) -> Component {
    let result = children.flatMap { $0 }
    print("buildBlock \(children) -> \(result)")
    return result
  }
  
  static func buildIf(_ children: Component?) -> Component {
    let result = children ?? []
    print("buildIf \(children as Any) -> \(result)")
    return result
  }
}

func testBlock(@TestBuilder makeChildren: () -> [Int]) -> [Int] {
  return makeChildren()
}

testBlock {
  if true {
    [1]
    if true {
      [2]
    }
  }
  [3]
  if true {
    [4]
    if false {
      [42]
    }
  }
  [5, 6]
}

```

This prints:

```swift
buildBlock [[2]] -> [2]
buildIf Optional([2]) -> [2]
buildBlock [[1], [2]] -> [1, 2]
buildIf Optional([1, 2]) -> [1, 2]
buildIf nil -> []
buildBlock [[4], []] -> [4]
buildIf Optional([4]) -> [4]
buildBlock [[1, 2], [3], [4], [5, 6]] -> [1, 2, 3, 4, 5, 6]

```

* * *

I'm worried about one particular thing with the current design. What if you release a module with a builder that has not specified every possible builder functions? Theoretically I as the module user can retroactively extend your builder type with custom builder functions and potentially alter the behaviour of the building behavior that can lead to unexpected results.

I hope you tracked this issue and I'd expect the compiler to emit errors on retroactively added builder functions from outside your own module boundary.

---

<div class="post-metadata">

**Author:** ![ExFalsoQuodlibet](https://avatars.discourse-cdn.com/v4/letter/e/bbce88/32.png) [@ExFalsoQuodlibet](https://forums.swift.org/u/ExFalsoQuodlibet)\
**Post date:** [June 14, 2019, 3:39pm UTC](https://forums.swift.org/t/function-builders/25167/278 "2019-06-14T15:39:42Z")

</div>

> [@anandabits](#):
>
> ### State
> 
> I agree that it may be useful for a DSL to be able to have a stateful builder even if the same basic design is followed. Maybe we should allow the builder to have a default initializer and use mutating instance methods instead of static methods. This would be a very minor change to the proposal - just initialize an instance of the builder and call instance methods on the instance instead of static methods on the type. If a builder didn't need state we could also support the static variant described by this proposal.

This is, to me, the most important point. We can work around all the limitations of the current proposal but this is a major one that will not allow function builders to go beyond the (rather simple) scope of the composite pattern: for example, any kind of context-aware computation could not be modeled with the current implementation, and that would be a gigantic miss, even for a first iteration.

---

<div class="post-metadata">

**Author:** ![Paul\_Cantrell](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/paul_cantrell/32/16764_2.png) [@Paul\_Cantrell](https://forums.swift.org/u/Paul_Cantrell)\
**Post date:** [June 14, 2019, 5:52pm UTC](https://forums.swift.org/t/function-builders/25167/279 "2019-06-14T17:52:02Z")

</div>

A question, and apologies if this is already answered somewhere:

How would the builder handle `Never`-returning functions? Would clients need to write `_ = fatalError(…)` inside a builder? Or would plain old `fatalError(…)` work?

The latter seems in keeping with the principle that `throws` works like normal without builder intervention, but seems like it would require a special exception in the proposal.

---

<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:** [June 14, 2019, 6:49pm UTC](https://forums.swift.org/t/function-builders/25167/280 "2019-06-14T18:49:09Z")

</div>

An overload of buildExpression that accepts Never and does nothing should do the trick.

---

<div class="post-metadata">

**Author:** ![GreatApe](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/greatape/32/2640_2.png) [@GreatApe](https://forums.swift.org/u/GreatApe)\
**Post date:** [June 14, 2019, 7:49pm UTC](https://forums.swift.org/t/function-builders/25167/281 "2019-06-14T19:49:40Z")

</div>

Ah but SwiftUI is not the language Swift, it's a framework, and it's a framework that completely transforms the way people makes apps, so I don't we should mind that involves some workarounds that can be removed in due time.

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

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