[Review] SE-0056: Allow trailing closures in `guard` conditions

If I understand you correctly, you think adding keywords represents an inconsistency.

I didn't write that, maybe I should have put my reply between your two paragraphs. Adding keywords such as 'then' and 'do' could add some consistency, but another word than 'do' will likely have to be found as 'do' could break code as highlighted by Xiaodi, as well as cause by the 'catch' case caught by Jeremy.

I was merely highlighting the current inconsistency of the variable scope of 'guard let' versus 'if let' which no one had mentioned so far... An inconsistency which is (logically) fully design intent and will remain forever. So some inconsistencies are acceptable,

Is accepting trailing closure in 'guard' really a new inconsistency?
Being unable to use them with 'guard', 'if', 'switch' is the original inconsistency as the trailing closure seemed to be use in many places (including argument list of another function). Adding 'guard' as a location where trailing closure are allowed doesn't really introduce a new inconsistency, it just incompletely reduce an existing inconsistency.

However, I think it would add considerable consistency and utility to the Swift language. Yes, it would make it inconsistent with the generations of C-like languages that have come before it. However, I think we've already taken considerable steps from away from C-like languages; for example, removing C-like for-loop syntax and unary increment/decrement operators.

I am with you here, Swift is Swift, C is C, Swift should not be hampered by keeping the syntax identical to C. But, it seems that most prefer to type less, so we should be really careful with proposing new keywords like this 'then' and 'do' as they carry little meaning, have to be mandatory (as per Chris), and are really needed only for trailing closure which will not be used by everyone.

So, I'm against adding these 'then' and 'do' keywords for the sake of providing the trailing support to 'if' and 'for'. And I do not see why we should prevent 'guard' from gaining this support just because the 'if' and 'for' doesn't also have it.

Dany

···

Le 4 avr. 2016 à 10:19, Patrick Gili <gili.patrick.r@gili-labs.com> a écrit :

On Apr 3, 2016, at 11:44 AM, Dany St-Amant via swift-evolution <swift-evolution@swift.org> wrote:

Le 2 avr. 2016 à 15:39, Patrick Gili via swift-evolution <swift-evolution@swift.org> a écrit :

What is your evaluation of the proposal?

I think there is a lot of value to allowing trailing closures in the guard condition clause. However, not at the cost of inconsistency. We have reviewed many proposals over the last month that addressed consistency issues in the Swift language, and if I'm not mistaken, all of them have been accepted by the community, larger to eliminate the inconsistency.

Because of this, I think two of the alternatives stated by the proposal have credibility:
1) Eliminate the "else" keyword from the guard syntax.
2) Add keywords to "if", "while", "for", and "switch" to delineate the condition clause from the body of the statement.

The second alternative has more appeal, because it supports trailing closures without "heroics".

It have been mentioned multiple times that allowing trailing closure only for guard is creating an inconsistency, but these keywords already are inconsistent with the each other (beside the presence of the 'trailing' else keyword) on the variable scoping:

- guard let: outer scope immutable variable
- if let: inner scope immutable variable
- for: inner scope immutable variable without let keyword

Consistency is good, but since each keywords are not for the exact same thing, it is normal to see some variances. Like the global scope of the immutable variable created by guard; as per the intent of the keyword, or its trailing else keyword; needed to clarify that what follow is for, for lack of better word, the 'else' case.

So as long as such inconsistency have a "raison d'être", that they have been designed and are not an oversight; there should be no reason to not allow them.

Dany

Is the problem being addressed significant enough to warrant a change to Swift?

No.

Does this proposal fit well with the feel and direction of Swift?

No. Please don't add inconsistencies to the language, as we're just going to have to deal with it down the road.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Not in my experience.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

In-depth study.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Although I use trailing closures a lot less now, I think I’m a +1 anyway for consistency’s sake.

I actually really like the idea of having trailing keywords in loops and if statements, these needn’t be required (except where a trailing closure is used) but for example it means I could do a fully natural language loop like:

     for eachValue in theValues do { … }

This is actually kind of bizarre. Here we are trying to invent new syntax so that the trailing closure can be used in if/while conditions and for sequences. However, there is already a perfectly good syntax for putting closures in these positions: put the closure in the parentheses of the function call. Are people really so desperate to use trailing closures everywhere that we have to add new keywords to the language? I don’t think they are.

While I kind of agree (and personally prefer the use of parenthesis in most places anyway) it’s an inconsistency to be unable to use them I think. While It’s understandable from a parsing/ambiguity perspective, it’s not really intuitive.

I think it's quite consistent. Trailing closures must be trailing.
Interpret that to mean that it must be the last thing surrounded by
braces, not just the last closure. If a function takes two closures,
only the last can be written with trailing closure syntax. In the
context of a control statement, if a block of code surrounded by
braces follows the closure, the closure cannot be written in trailing
closure syntax. By your argument for "consistency," all closures
should be allowed to be written in trailing syntax, so that for `func
foo(_: Int, _: () -> (), _: () -> ())`, I should be able to write
`func foo(2) { /* code */ } { /* code */ }`. I don't think we need
that level of "consistency."

···

On Mon, Apr 4, 2016 at 11:18 AM, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

On 4 Apr 2016, at 15:49, Jeremy Pereira <jeremy.j.pereira@googlemail.com> wrote:

On 3 Apr 2016, at 17:20, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

I like the consistency of every block having a kind of type (do, else, defer, catch etc.).

That is a rabbit hole down which you probably shouldn't go. If we go down the route of blocks having a “type”, the current situation in Swift becomes somewhat inconsistent. I would argue that the `else` block on a `guard` is of a different type to the `else` block on an `if`. If anything, the `else` block of an `if` is closer to the `then` block. Also, would you allow the `do` block in a `for` or `while` to have a `catch` block following it? If not, then these blocks are different to the existing bare `do` block.

Actually that’s not quite what I meant by “type”; while there is a case to be made for unifying these more (else and catch on loops for example) I just meant more along the lines that “do” would always group the main branch, “else” indicates an alternative path if a condition isn’t met and so-on. For the short term however this would just be a case of allowing do on the end to eliminate ambiguity and thus allow trailing closures, but in the long term it could be explored further.

FWIW adding 'then' would allow using 'if' as an expression by replacing the {...} blocks with expressions. One argument against 'if' expressions was that { } are ugly within an expression. So there might be a benefit besides providing trailing support.

-Thorsten

···

Am 05.04.2016 um 01:52 schrieb Dany St-Amant via swift-evolution <swift-evolution@swift.org>:.

I am with you here, Swift is Swift, C is C, Swift should not be hampered by keeping the syntax identical to C. But, it seems that most prefer to type less, so we should be really careful with proposing new keywords like this 'then' and 'do' as they carry little meaning, have to be mandatory (as per Chris), and are really needed only for trailing closure which will not be used by everyone.

So, I'm against adding these 'then' and 'do' keywords for the sake of providing the trailing support to 'if' and 'for'.

Although I use trailing closures a lot less now, I think I’m a +1 anyway for consistency’s sake.

I actually really like the idea of having trailing keywords in loops and if statements, these needn’t be required (except where a trailing closure is used) but for example it means I could do a fully natural language loop like:

  for eachValue in theValues do { … }

This is actually kind of bizarre. Here we are trying to invent new syntax so that the trailing closure can be used in if/while conditions and for sequences. However, there is already a perfectly good syntax for putting closures in these positions: put the closure in the parentheses of the function call. Are people really so desperate to use trailing closures everywhere that we have to add new keywords to the language? I don’t think they are.

While I kind of agree (and personally prefer the use of parenthesis in most places anyway) it’s an inconsistency to be unable to use them I think. While It’s understandable from a parsing/ambiguity perspective, it’s not really intuitive.

But the resolution would be another inconsistency i.e. a separate keyword that is only required if the condition has a trailing closure. Furthermore, that is an inconsistency that adds extra complexity to the language.

I like the consistency of every block having a kind of type (do, else, defer, catch etc.).

That is a rabbit hole down which you probably shouldn't go. If we go down the route of blocks having a “type”, the current situation in Swift becomes somewhat inconsistent. I would argue that the `else` block on a `guard` is of a different type to the `else` block on an `if`. If anything, the `else` block of an `if` is closer to the `then` block. Also, would you allow the `do` block in a `for` or `while` to have a `catch` block following it? If not, then these blocks are different to the existing bare `do` block.

Actually that’s not quite what I meant by “type”; while there is a case to be made for unifying these more (else and catch on loops for example) I just meant more along the lines that “do” would always group the main branch, “else” indicates an alternative path if a condition isn’t met and so-on. For the short term however this would just be a case of allowing do on the end to eliminate ambiguity and thus allow trailing closures, but in the long term it could be explored further.

I don’t view the `else` on an `if` as being some kind of second class citizen, it’s simply one of two alternate execution paths, whereas the `else` on a `guard` really is a second class citizen - it is even restricted what you can put in the block i.e. it must cause the enclosing scope to be exited.

The reason why I called it a rabbit hole is because regarding the keyword in front of a block as denoting the kind of block it is, leads us to having to change a lot in order to make it meaningful and consistent.

···

On 4 Apr 2016, at 18:18, Haravikk <swift-evolution@haravikk.me> wrote:

On 4 Apr 2016, at 15:49, Jeremy Pereira <jeremy.j.pereira@googlemail.com> wrote:

On 3 Apr 2016, at 17:20, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

Yet another inconsistency in this area (for people who care about them)

While the 'while {}' does not support trailing closures, the 'repeat {} while' does support them. So, will the folks against supporting them in 'guard' ask for a change to drop the support in the 'repeat {} while'?

Dany

···

Le 4 avr. 2016 à 19:52, Dany St-Amant via swift-evolution <swift-evolution@swift.org> a écrit :

Le 4 avr. 2016 à 10:19, Patrick Gili <gili.patrick.r@gili-labs.com> a écrit :

If I understand you correctly, you think adding keywords represents an inconsistency.

I didn't write that, maybe I should have put my reply between your two paragraphs. Adding keywords such as 'then' and 'do' could add some consistency, but another word than 'do' will likely have to be found as 'do' could break code as highlighted by Xiaodi, as well as cause by the 'catch' case caught by Jeremy.

I was merely highlighting the current inconsistency of the variable scope of 'guard let' versus 'if let' which no one had mentioned so far... An inconsistency which is (logically) fully design intent and will remain forever. So some inconsistencies are acceptable,

Is accepting trailing closure in 'guard' really a new inconsistency?
Being unable to use them with 'guard', 'if', 'switch' is the original inconsistency as the trailing closure seemed to be use in many places (including argument list of another function). Adding 'guard' as a location where trailing closure are allowed doesn't really introduce a new inconsistency, it just incompletely reduce an existing inconsistency.

However, I think it would add considerable consistency and utility to the Swift language. Yes, it would make it inconsistent with the generations of C-like languages that have come before it. However, I think we've already taken considerable steps from away from C-like languages; for example, removing C-like for-loop syntax and unary increment/decrement operators.

I am with you here, Swift is Swift, C is C, Swift should not be hampered by keeping the syntax identical to C. But, it seems that most prefer to type less, so we should be really careful with proposing new keywords like this 'then' and 'do' as they carry little meaning, have to be mandatory (as per Chris), and are really needed only for trailing closure which will not be used by everyone.

So, I'm against adding these 'then' and 'do' keywords for the sake of providing the trailing support to 'if' and 'for'. And I do not see why we should prevent 'guard' from gaining this support just because the 'if' and 'for' doesn't also have it.

Dany

On Apr 3, 2016, at 11:44 AM, Dany St-Amant via swift-evolution <swift-evolution@swift.org> wrote:

Le 2 avr. 2016 à 15:39, Patrick Gili via swift-evolution <swift-evolution@swift.org> a écrit :

What is your evaluation of the proposal?

I think there is a lot of value to allowing trailing closures in the guard condition clause. However, not at the cost of inconsistency. We have reviewed many proposals over the last month that addressed consistency issues in the Swift language, and if I'm not mistaken, all of them have been accepted by the community, larger to eliminate the inconsistency.

Because of this, I think two of the alternatives stated by the proposal have credibility:
1) Eliminate the "else" keyword from the guard syntax.
2) Add keywords to "if", "while", "for", and "switch" to delineate the condition clause from the body of the statement.

The second alternative has more appeal, because it supports trailing closures without "heroics".

It have been mentioned multiple times that allowing trailing closure only for guard is creating an inconsistency, but these keywords already are inconsistent with the each other (beside the presence of the 'trailing' else keyword) on the variable scoping:

- guard let: outer scope immutable variable
- if let: inner scope immutable variable
- for: inner scope immutable variable without let keyword

Consistency is good, but since each keywords are not for the exact same thing, it is normal to see some variances. Like the global scope of the immutable variable created by guard; as per the intent of the keyword, or its trailing else keyword; needed to clarify that what follow is for, for lack of better word, the 'else' case.

So as long as such inconsistency have a "raison d'être", that they have been designed and are not an oversight; there should be no reason to not allow them.

Dany

Is the problem being addressed significant enough to warrant a change to Swift?

No.

Does this proposal fit well with the feel and direction of Swift?

No. Please don't add inconsistencies to the language, as we're just going to have to deal with it down the road.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Not in my experience.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

In-depth study.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution