# Pitch: Double (or more) trailing closures

**URL:** <https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147>\
**Category:** Pitches\
**Created:** [September 25, 2019, 9:34am UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147 "2019-09-25T09:34:05Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![elhoov](https://avatars.discourse-cdn.com/v4/letter/e/47e85d/32.png) [@elhoov](https://forums.swift.org/u/elhoov)\
**Post date:** [September 25, 2019, 9:34am UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/1 "2019-09-25T09:34:05Z")

</div>

I think there's a beauty and consistency in being able to re-implement parts of the language without having to use meta-programming. An example of this would be implementing if with an auto-closure and a trailing closure. I propose extending that to support more than one trailing closure, so we could re-implement if else for example. It would be something like:

```
func when<T>(condition: @autoclosure () -> Bool, then trueBranch: () -> T, `else` falseBranch: () -> T) -> T {
    if condition() {
        return trueBranch()
    } else {
        return falseBranch()
    }
}

let a = when (2 < 3) { 3 } else { 4 };

```

So the first closure would work like a trailing closure works right now, and the rest would be separated by the argument label.

Update: As brought up by others, there might be a problem with ambiguity, so I propose to enforce a semicolon at the end in the case of trailing closures. Also I would be in favor of being able to remove the parenthesis if the case of a single argument before the first closure, as in `when 2 < 3 {3} else {4}` but that might be best as a separate pitch.

---

<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:** [September 25, 2019, 12:14pm UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/2 "2019-09-25T12:14:48Z")

</div>

it’s an interesting idea, though the (machine) parsing looks hard. I’ll need to think about it some more. 🤔

---

<div class="post-metadata">

**Author:** ![elhoov](https://avatars.discourse-cdn.com/v4/letter/e/47e85d/32.png) [@elhoov](https://forums.swift.org/u/elhoov)\
**Post date:** [September 25, 2019, 12:17pm UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/3 "2019-09-25T12:17:28Z")

</div>

Yeah I was about to add a note about that at the end, but then realized I don't know what I'm talking about so I just left it for people who do 🙂 .

P.S. It's probably reasonable to disallow keywords that can start a statement in this case, like if, for etc. which would remove ambiguity in parsing, but ones like else should be fine imho.

---

<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:** [September 25, 2019, 12:25pm UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/4 "2019-09-25T12:25:26Z")

</div>

There’s also this problem that the trailing closure could get picked up as a separated statement:

```swift
func when<T>(condition: @autoclosure () -> Bool, then trueBranch: () -> T, otherwise falseBranch: () -> T) -> T { ... }

when(2 < 3) { doSomething() }
// Is this a separated statement?
// How do we know it’s a continuation?
otherwise { doSomethineElse() }

```

PS  
`@autoclosure` is used when you don’t want to write out a closure. You can’t even if you want to, so that’s probably not what you want here.

---

<div class="post-metadata">

**Author:** ![elhoov](https://avatars.discourse-cdn.com/v4/letter/e/47e85d/32.png) [@elhoov](https://forums.swift.org/u/elhoov)\
**Post date:** [September 25, 2019, 12:31pm UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/5 "2019-09-25T12:31:14Z")

</div>

Not sure if you need to disambiguate before, but at the semantical layer you would know because the the otherwise parameter is unfulfilled so there's just one way to interpret it. This does however raise the issue of what happens if otherwise is optional. Maybe that should be disallowed.

PS: you're absolutely right, I've been testing it locally as `let x = when(2 < 3, 3, 4)` but forgot to remove the autoclosure.

---

<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:** [September 25, 2019, 12:36pm UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/6 "2019-09-25T12:36:22Z")

</div>

I would prefer a syntax that works even in the presence of optional and overloads. Otherwise it’d be too limited to be useful.

Marking arguments with `:` could be confused with labeling too.

---

<div class="post-metadata">

**Author:** ![elhoov](https://avatars.discourse-cdn.com/v4/letter/e/47e85d/32.png) [@elhoov](https://forums.swift.org/u/elhoov)\
**Post date:** [September 25, 2019, 12:45pm UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/7 "2019-09-25T12:45:27Z")

</div>

Also adding `:` defeats the purpose. Without `:` it serves as a mental model that's consistent with if else, with `:` it's just another special case that adds more mental overhead. I can't think of a way to make it non-ambiguous if they can be optional and overloaded except forcing a semicolon at the end of the statement. Correct me if I'm wrong but it seems like that would make parsing possible, not sure if it's desirable though.

---

<div class="post-metadata">

**Author:** ![toph42](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/toph42/32/7807_2.png) [@toph42](https://forums.swift.org/u/toph42)\
**Post date:** [September 25, 2019, 1:55pm UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/8 "2019-09-25T13:55:55Z")

</div>

> [@elhoov](#):
>
> `let a = when (2 < 3) { 3 } else { 4 }`

Why is this not just the ternary operator?  
`let a = (2 < 3) ? 3 : 4`  
This provides the same result. Perhaps there’s another concrete example that demonstrates the point?

---

<div class="post-metadata">

**Author:** ![elhoov](https://avatars.discourse-cdn.com/v4/letter/e/47e85d/32.png) [@elhoov](https://forums.swift.org/u/elhoov)\
**Post date:** [September 25, 2019, 2:05pm UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/9 "2019-09-25T14:05:15Z")

</div>

Of course the example can be substituted by the ternary, I'm not suggesting that we add when to the language it's just an example that it would be possible to implement things that look like language features with just plain functions. This is something that would just be useful for creating DSLs, so while I can think of a few examples they are by definition too narrow to be good for illustrating the proposal.

---

<div class="post-metadata">

**Author:** ![toph42](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/toph42/32/7807_2.png) [@toph42](https://forums.swift.org/u/toph42)\
**Post date:** [September 25, 2019, 2:08pm UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/10 "2019-09-25T14:08:20Z")

</div>

While on a philosophical level I can appreciate a “I can’t wait to see what people make with these building blocks” attitude, it seems to me that a demonstrable use case is a reasonable ask for a pitch for new language features.

To be clear, I mean something that’s not trivially doable with existing language features, like the given example in this case.

---

<div class="post-metadata">

**Author:** ![elhoov](https://avatars.discourse-cdn.com/v4/letter/e/47e85d/32.png) [@elhoov](https://forums.swift.org/u/elhoov)\
**Post date:** [September 25, 2019, 2:19pm UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/11 "2019-09-25T14:19:20Z")

</div>

Ok, I'll try my best. While it may have other use cases, I think this is mostly useful when there's something that acts like a callback. In my field (data engineering) this is often creating DAGs, that get defined at some point but executed at a later point. While I think that could make a nice DSL I'm assuming most people aren't familiar with something like [https://airflow.apache.org/](https://airflow.apache.org/) to make a good example so I'll just use plain old javascript-like callbacks as an example. Say we wanted to create a library like axios, where you define a request like:

```
axios.get('/user?ID=12345')
  .then(function (response) {
    // handle success
    console.log(response);
  })
  .catch(function (error) {
    // handle error
    console.log(error);
  })
  .finally(function () {
    // always executed
  });

```

In swift with this proposal this could be written as:

```
requests.get("/user?ID=12345") { response in
    let user = response.args["user"]
    ...
} catch {
    print("Something went wrong")
} finally {
    // Always execute
};

```

I added the semicolon because I think having it mandatory is the only way to parse it easily.

---

<div class="post-metadata">

**Author:** ![Pampel](https://avatars.discourse-cdn.com/v4/letter/p/3da27b/32.png) [@Pampel](https://forums.swift.org/u/Pampel)\
**Post date:** [September 26, 2019, 9:40am UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/12 "2019-09-26T09:40:51Z")

</div>

Just a nitpick, but wouldn't...

> [@elhoov](#):
>
> `let a = when (2 < 3) { 3 } else { 4 }`

...given your original example actually have to be written...  
`let a = when (2 < 3) then { 3 } else { 4 }`

I really like the pitch, I've wanted something like this many times.

---

<div class="post-metadata">

**Author:** ![donny\_wals](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/donny_wals/32/24944_2.png) [@donny\_wals](https://forums.swift.org/u/donny_wals)\
**Post date:** [September 26, 2019, 10:08am UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/13 "2019-09-26T10:08:53Z")

</div>

I don't like this at all, it would make it very hard to see what closure is there as a part of the bigger function call, which are part of language keywords (in that example `catch` is a reserved keyword) and which are part of a new method call:

```swift
requests.get("/user?ID=12345") { response in
    let user = response.args["user"]
    ...
}
andThen { 
  // do something else
}
finally {
  // do something more
}

```

the above would be reasonable in this proposal but there is no way of knowing whether `andThen` is a separate function or part of `requests.get`. On top of that, the following is also something that you might write:

```swift
requests.get("/user?ID=12345") { response in
    let user = response.args["user"]
    ...
}
.andThen { 
  // do something else
}
.finally {
  // do something more
}

```

The difference is so subtle that it's easy to miss when scanning code and can easily lead to confusion.

What I would possibly be in favor of is requiring `:` to make it somewhat clearer that we're dealing with a function argument. Might also be too subtle though but it at least looks very similar to existing syntax:

```swift
requests.get("/user?ID=12345") { response in
    let user = response.args["user"]
    ...
} 
catch: {
    print("Something went wrong")
} 
finally: {
    // Always execute
};

```

---

<div class="post-metadata">

**Author:** ![elhoov](https://avatars.discourse-cdn.com/v4/letter/e/47e85d/32.png) [@elhoov](https://forums.swift.org/u/elhoov)\
**Post date:** [September 26, 2019, 10:20am UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/14 "2019-09-26T10:20:29Z")

</div>

I proposed omitting the first label so it's consistent with if/while/for syntax, but I guess if it's preferable it could be omitted only if the label is \_.

---

<div class="post-metadata">

**Author:** ![elhoov](https://avatars.discourse-cdn.com/v4/letter/e/47e85d/32.png) [@elhoov](https://forums.swift.org/u/elhoov)\
**Post date:** [September 26, 2019, 10:27am UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/15 "2019-09-26T10:27:00Z")

</div>

Thanks for the constructive criticism.

> [@donny\_wals](#):
>
> the above would be reasonable in this proposal but there is no way of knowing whether `andThen` is a separate function or part of `requests.get` . On top of that, the following is also something that you might write:

That's why I proposed enforcing a semicolon at the end for multiple trailing closures. This would solve the parsing/ambiguity problem, right? I guess it's a matter of taste whether a mandatory semicolon at the end is a good idea or not, but I prefer it to using `:` because that would be another special case, whereas with `myIf (2 < 3) { A() } else { B() };` it's consistent since if you substituted myIf with if it's valid code, and it's a mental model you already have.

I'm also in favour of being able to drop the parenthesis if there's just one argument before a trailing closure to make it even more consistent.

---

<div class="post-metadata">

**Author:** ![donny\_wals](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/donny_wals/32/24944_2.png) [@donny\_wals](https://forums.swift.org/u/donny_wals)\
**Post date:** [September 26, 2019, 10:29am UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/16 "2019-09-26T10:29:47Z")

</div>

> [@elhoov](#):
>
> I guess it's a matter of taste whether a mandatory semicolon at the end is a good idea or not

I don't think there's any part in the Swift language where a semicolon is mandatory, they're always optional. Making them mandatory for this feature seems very counterintuitive and not in-line with Swift standards IMO.

---

<div class="post-metadata">

**Author:** ![elhoov](https://avatars.discourse-cdn.com/v4/letter/e/47e85d/32.png) [@elhoov](https://forums.swift.org/u/elhoov)\
**Post date:** [September 26, 2019, 10:36am UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/17 "2019-09-26T10:36:01Z")

</div>

Depends on how you look at it. They're mandatory whenever it's not clear where a statement finishes and another one starts (which as far as I know is just when there's more than one statement per line). This would be introducing one more case where it's unclear, thus it could be argued that it's reasonable to resolve it with a semicolon.

---

<div class="post-metadata">

**Author:** ![donny\_wals](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/donny_wals/32/24944_2.png) [@donny\_wals](https://forums.swift.org/u/donny_wals)\
**Post date:** [September 26, 2019, 10:49am UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/18 "2019-09-26T10:49:47Z")

</div>

I see your point but I don't think it's clear here that we're looking at one long statement:

```swift
requests.get("/user?ID=12345") { response in
    let user = response.args["user"]
    ...
}
andThen { 
  // do something else
}
finally {
  // do something more
};

```

This would also be valid code without multiple trailing closure syntax. We'd just consider the `;` out of place.

---

<div class="post-metadata">

**Author:** ![elhoov](https://avatars.discourse-cdn.com/v4/letter/e/47e85d/32.png) [@elhoov](https://forums.swift.org/u/elhoov)\
**Post date:** [September 26, 2019, 11:14am UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/19 "2019-09-26T11:14:14Z")

</div>

Yeah I see your point too, but it's mostly because of how you formatted the code. Maybe it's better to **only** allow this kind of syntax if the labels are keywords that can't be a start of a statement (eg: else, catch, finally but not if, else, for). My guess is that most of the cases where this is useful can fit into those keywords. It's also consistent with existing statements by not introducing new "pseudo-keywords" and doesn't require a semicolon at the end.

---

<div class="post-metadata">

**Author:** ![thomasvl](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/thomasvl/32/3033_2.png) [@thomasvl](https://forums.swift.org/u/thomasvl)\
**Post date:** [September 26, 2019, 4:35pm UTC](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147/20 "2019-09-26T16:35:10Z")

</div>

![](https://global.discourse-cdn.com/swift/original/2X/1/1be030d9e7dd23eb094898a53acfc93633159b04.jpeg) donny\_wals:

> the above would be reasonable in this proposal but there is no way of knowing whether `andThen` is a separate function or part of `requests.get` . On top of that, the following is also something that you might write:

> [@elhoov](#):
>
> That's why I proposed enforcing a semicolon at the end for multiple trailing closures. This would solve the parsing/ambiguity problem, right? I guess it's a matter of taste whether a mandatory semicolon at the end is a good idea or not, but I prefer it to using `:` because that would be another special case, whereas with `myIf (2 < 3) { A() } else { B() };` it's consistent since if you substituted myIf with if it's valid code, and it's a mental model you already have.

fyi - I don't think the semicolon solves it. Looking at the `requests.get` example again:

```swift
requests.get("/user?ID=12345") { response in
    let user = response.args["user"]
    ...
}
andThen { 
  // do something else
}
finally {
  // do something more
};

```

Does `requests.get` take three trailing closures or does it just take one and `andThen` take two? i.e. - it marks the end, but what lets someone tell where the trailing closures start?

edit: actually, it's worse. What if `requests.get` only takes one closure and `andThen` is a second call. Then a new release of `requests` comes out and it gets a new `get` method with the two additional trailing closures. Suddenly what was compiled one way would not get compiled another way, no?

[Next page](https://forums.swift.org/t/pitch-double-or-more-trailing-closures/29147.md?page=2)
