[swift-evolution] [proposal] Allow trailing closures in 'guard' conditions

Ilya Belenkiy ilya.belenkiy at gmail.com
Wed Mar 23 07:27:01 CDT 2016

+1, a very useful change. I'd use it in lots of places in my code.

On Wed, Mar 23, 2016 at 2:03 AM Chris Lattner via swift-evolution <
swift-evolution at swift.org> wrote:

> Hi everyone,
> This is a proposal for a very narrow extension to the guard statement.  I
> consider it to be a bug fix, but since it is a language extension, I feel
> that it should go through the evolution process.  Thoughts appreciated!
> -Chris
> *Introduction & Motivation*
> The three statements `if`, `while`, and `guard` form a family that all
> take a rich form of conditions that can include one or more boolean
> conditions, `#available` clauses, and `let`/`case` pattern bindings.  These
> are described by the `condition-clause` production in the TSPL reference
> section and as a `stmt-condition` in the compiler source code.
> Today, these do not permit trailing closures in any top-level expressions
> embedded in the condition, because that would be generally ambiguous with
> the body of an if or while statement:
> if foo {   // start of trailing closure, or start of the if body?
> While it would be possible to tell what is intended in some cases by
> performing arbitrary lookahead or by performing type checking while
> parsing, these approaches have significant consequences for the
> architecture for the compiler.  As such, we’ve opted keep the parser simple
> and disallow this.  Unrelated to this proposal, I landed a patch (
> https://github.com/apple/swift/commit/30ec0f4128525a16f998e04ae8b1f70180627446)
> which *greatly* improves the error messages in some of the most common
> cases where a developer accidentally tries to do this.
> However, while this approach makes sense for `if` and `while` statements,
> it does not make sense for ‘guard': The body of a guard statement is
> delineated by the `else` keyword, so there is no ambiguity.  A brace is
> always the start of a trailing closure.
> From a historical perspective, the current situation was an oversight.  An
> earlier design for `guard` did not include the `else` keyword (it used the
> `unless` keyword), and I forgot to fix this when we decided to resyntax it
> to `guard/else`.
> *Proposed solution*
> The solution is simple: allow trailing closures in guard bodies.  This
> would allow this silly example to compile correctly:
> func f(arr : [Int]?) {
>   guard let x = arr?.map {$0+1} else {
>     preconditionFailure()
>   }
>   // ...
> }
> *Detailed Design*
> The impact on the compiler is trivial, here’s a patch:
> *Impact on existing code*
> There is no impact on existing code.  This only makes formerly invalid
> code start being accepted.
> *Alternatives considered*
> There are three primary alternatives: do nothing, expand the scope of ‘if'
> and ‘while’ conditions as well, and significantly change the syntax of
> guard.
> *Do nothing*: It can be argued that this change would make guard
> inconsistent with the restrictions of ‘if’ and ‘while’ and that
> inconsistency would be confusing.  On the other hand, I am arguing that
> this is an arbitrary restriction.
> *Expand the scope of “if” and “while” statements:*  Through enough
> heroics and lookahead we could consider relaxing the trailing closure
> requirements on `if` and `while` statements as well.  While this could be
> interesting, it raises several ambiguity questions.  For example, we need
> significant lookahead to realize that “a” here is not a trailing closure,
> since we have a closure expression being fully applied after it:
> if foo { …a... } { …b… }()
> this could be addressed with whitespace rules or other approaches, but
> since any such direction would be compatible with this proposal, I see it
> as a separable potential extension on top of this basic proposal.
> *Change the syntax of guard: *I only list this for completeness, but we
> could eliminate the `else` keyword, making guard more similar to `if` and
> `while`.  I personally think that this is a really bad idea though: the
> guard statement is not a general `unless` statement, and its current syntax
> was very very carefully evaluated, iterated on, discussed, and re-evaluated
> in the Swift 2 timeframe.  I feel that it has stood the test of time well
> since then.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160323/20199faa/attachment.html>

More information about the swift-evolution mailing list