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

Xiaodi Wu xiaodi.wu at gmail.com
Wed Mar 23 21:38:40 CDT 2016


To be fair, mandatory `else` breaks the symmetry between `guard` and
other control statements. Given that it's not symmetrical as it is,
I'm +1 on the proposal.


On Wed, Mar 23, 2016 at 6:06 PM, Rudolf Adamkovic via swift-evolution
<swift-evolution at swift.org> wrote:
> I'm +1 and -1 at the same time.
>
> It's handy but breaks consistency between guard and all the other control
> flow statements.
>
> R+
>
> Sent from my iPhone
>
> On 23 Mar 2016, at 07:03, 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:
>
> <guard.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
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>


More information about the swift-evolution mailing list