[Pitch] making where and , interchangeable in guard conditions.


(Erica Sadun) #1

Earlier on Swift Evolution:

Me: "Is there a technical reason that Swift cannot be expanded to allow arbitrary mixes of conditional binding and boolean assertions within a single compound guard statement?"

Joe Groff: "No. You already can, we just have the somewhat strange rule that to separate `guard` conditions uses `,` before optional or pattern conditions, but `where` before Boolean conditions. There's no technical reason we couldn't accept either 'where' or ',' consistently."

  guard x == 0,
    let y = optional where
    z == 2 {
  }

Pitch:

I'd like to update Swift's grammar to interchangeably and consistently accept `where` or `,` to separate guard conditions. This would allow a more consistent approach that supports intermingling conditional binding and boolean assertions. Here's a real-world bit of code I was helping someone with a few evenings ago. It's attempting to navigate through some JSON, using optional conditions with where clauses.

guard
    let fileContents = fileContents,
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as? NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray where featuresArray.count > 0,
    let featuresDict = featuresArray[0] as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"] where coordinatesArray.count > 0,
    let coordinateArray = coordinatesArray[0] as? NSArray where coordinateArray.count > 3
    else { fatalError("Reason") }

Each `where` test is a separate test. While there are semantic ties between the conditional binding and the count tests, there doesn't have to be. Under Swift's current rules, you must use the `where` keyword to introduce a Boolean test after a binding or pattern, regardless of whether or not there's an underlying semantic link between the two.

By removing this requirement and allowing interchangeability between `where` and `,`, you're given the option of tying the boolean to the binding/pattern match or introducing a boolean statement with no connection to previous steps. Here's what this example looks like after excluding `where`:

guard
    let fileContents = fileContents,
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as? NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray,
    featuresArray.count > 0,
    let featuresDict = featuresArray.firstObject as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"],
    coordinatesArray.count > 0,
    let coordinateArray = coordinatesArray.firstObject as? NSArray,
    coordinateArray.count > 3
    else { fatalError("Reason") }

The motivation for this approach becomes more compelling when the Boolean tests are disjoint from binding or pattern matches.

guard
    minimumShapeCount > 4,
    let shapes = decompose(map, minimum: minimumShapeCount),
    availableArea > minimumArea,
    let map = placeShapes(shapes, availableArea) else {
        fatalError()
}

would be allowed compared to current Swift which mandates where between the second and third tests:

    let shapes = decompose(map, minimum: minimumShapeCount) where availableArea > minimumArea,

In my vision, Swift would continue to allow where clauses and expand to allow disjoint Boolean entries.

Thoughts?

-- E


(Xiaodi Wu) #2

I agree `guard let y = optional where z == 2` reads quite strangely.

To me, though, it could make sense if variables bound in a guard statement
are restricted to a boolean assertion only after a `where`, but unrelated
boolean assertions should definitely not require it (i.e. `guard let y =
optional where y == 2` does seem more sensible than `guard let y =
optional, y == 2`, but `guard let y = optional where z == 2` is unpleasant.)

···

On Fri, May 20, 2016 at 12:07 PM, Erica Sadun via swift-evolution < swift-evolution@swift.org> wrote:

*Earlier on Swift Evolution:*

Me: "*Is there a technical reason that Swift cannot be expanded to allow
arbitrary mixes of conditional binding and boolean assertions within a
single compound guard statement?*"

Joe Groff: "*No. You already can, we just have the somewhat strange rule
that to separate `guard` conditions uses `,` before optional or pattern
conditions, but `where` before Boolean conditions. **There's no technical
reason we couldn't accept either 'where' or ',' consistently."*

guard x == 0,
let y = optional where
z == 2 {
}

*Pitch: *

I'd like to update Swift's grammar to interchangeably and consistently
accept `where` or `,` to separate guard conditions. This would allow a more
consistent approach that supports intermingling conditional binding and
boolean assertions. Here's a real-world bit of code I was helping someone
with a few evenings ago. It's attempting to navigate through some JSON,
using optional conditions with where clauses.

guard
    let fileContents = fileContents,
    let jsonDict = try
NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as?
NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray *where **featuresArray.count
> 0,*
    let featuresDict = featuresArray[0] as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"] *where **coordinatesArray.count
> 0,*
    let coordinateArray = coordinatesArray[0] as? NSArray *where **coordinateArray.count
> 3*
    else { fatalError("Reason") }

Each `where` test is a separate test. While there *are* semantic ties
between the conditional binding and the count tests, there *doesn't have
to be*. Under Swift's current rules, you must use the `where` keyword to
introduce a Boolean test after a binding or pattern, regardless of whether
or not there's an underlying semantic link between the two.

By removing this requirement and allowing interchangeability between
`where` and `,`, you're given the option of tying the boolean to the
binding/pattern match or introducing a boolean statement with no connection
to previous steps. Here's what this example looks like after excluding
`where`:

guard
    let fileContents = fileContents,
    let jsonDict = try
NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as?
NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray,
* featuresArray.count > 0,*
    let featuresDict = featuresArray.firstObject as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"],
* coordinatesArray.count > 0,*
    let coordinateArray = coordinatesArray.firstObject as? NSArray,
    *coordinateArray.count > 3*
    else { fatalError("Reason") }

The motivation for this approach becomes more compelling when the Boolean
tests are disjoint from binding or pattern matches.

guard
    minimumShapeCount > 4,
    let shapes = decompose(map, minimum: minimumShapeCount),
    availableArea > minimumArea,
    let map = placeShapes(shapes, availableArea) else {
        fatalError()
}

would be allowed compared to current Swift which mandates where between
the second and third tests:

    let shapes = decompose(map, minimum: minimumShapeCount) where availableArea
> minimumArea,

In my vision, Swift would continue to allow where clauses and expand to
allow disjoint Boolean entries.

Thoughts?

-- E

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


(Matthew Johnson) #3

Earlier on Swift Evolution:

Me: "Is there a technical reason that Swift cannot be expanded to allow arbitrary mixes of conditional binding and boolean assertions within a single compound guard statement?"

Joe Groff: "No. You already can, we just have the somewhat strange rule that to separate `guard` conditions uses `,` before optional or pattern conditions, but `where` before Boolean conditions. There's no technical reason we couldn't accept either 'where' or ',' consistently."

  guard x == 0,
    let y = optional where
    z == 2 {
  }

Pitch:

I'd like to update Swift's grammar to interchangeably and consistently accept `where` or `,` to separate guard conditions. This would allow a more consistent approach that supports intermingling conditional binding and boolean assertions. Here's a real-world bit of code I was helping someone with a few evenings ago. It's attempting to navigate through some JSON, using optional conditions with where clauses.

guard
    let fileContents = fileContents,
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as? NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray where featuresArray.count > 0,
    let featuresDict = featuresArray[0] as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"] where coordinatesArray.count > 0,
    let coordinateArray = coordinatesArray[0] as? NSArray where coordinateArray.count > 3
    else { fatalError("Reason") }

Each `where` test is a separate test. While there are semantic ties between the conditional binding and the count tests, there doesn't have to be. Under Swift's current rules, you must use the `where` keyword to introduce a Boolean test after a binding or pattern, regardless of whether or not there's an underlying semantic link between the two.

By removing this requirement and allowing interchangeability between `where` and `,`, you're given the option of tying the boolean to the binding/pattern match or introducing a boolean statement with no connection to previous steps. Here's what this example looks like after excluding `where`:

guard
    let fileContents = fileContents,
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as? NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray,
    featuresArray.count > 0,
    let featuresDict = featuresArray.firstObject as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"],
    coordinatesArray.count > 0,
    let coordinateArray = coordinatesArray.firstObject as? NSArray,
    coordinateArray.count > 3
    else { fatalError("Reason") }

The motivation for this approach becomes more compelling when the Boolean tests are disjoint from binding or pattern matches.

You can already format the code in a pretty similar way although it is slightly awkward because some lines are required to have commas and others must *not* have commas:

guard
    let fileContents = fileContents,
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as? NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray
    where featuresArray.count > 0,
    let featuresDict = featuresArray[0] as? NSDictionary,
    let coordinatesArray = featuresDict["geometry”]
    where coordinatesArray.count > 0,
    let coordinateArray = coordinatesArray[0] as? NSArray
    where coordinateArray.count > 3
    else { fatalError("Reason") }

I agree that it would be good to allow boolean expressions to be stand alone clauses in order to support formatting like this without the inconsistency with regards to commas.

I am less certain about allowing simple boolean expressions that are not introduced by the `where` keyword (excepting the first one which is introduced with the `guard` keyword). I think this is a separate question that should receive independent consideration. I think a reasonable argument can be made both ways.

Also, looking at these examples I can’t help but notice a another case of a comma separated list that would benefit from allowing newline to be used in place of the commas as well.

···

On May 20, 2016, at 12:07 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

guard
    minimumShapeCount > 4,
    let shapes = decompose(map, minimum: minimumShapeCount),
    availableArea > minimumArea,
    let map = placeShapes(shapes, availableArea) else {
        fatalError()
}

would be allowed compared to current Swift which mandates where between the second and third tests:

    let shapes = decompose(map, minimum: minimumShapeCount) where availableArea > minimumArea,

In my vision, Swift would continue to allow where clauses and expand to allow disjoint Boolean entries.

Thoughts?

-- E

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


(L Mihalkovic) #4

Earlier on Swift Evolution:

Me: "Is there a technical reason that Swift cannot be expanded to allow arbitrary mixes of conditional binding and boolean assertions within a single compound guard statement?"

Joe Groff: "No. You already can, we just have the somewhat strange rule that to separate `guard` conditions uses `,` before optional or pattern conditions, but `where` before Boolean conditions. There's no technical reason we couldn't accept either 'where' or ',' consistently."

  guard x == 0,
    let y = optional where
    z == 2 {
  }

Pitch:

I'd like to update Swift's grammar to interchangeably and consistently accept `where` or `,` to separate guard conditions. This would allow a more consistent approach that supports intermingling conditional binding and boolean assertions. Here's a real-world bit of code I was helping someone with a few evenings ago. It's attempting to navigate through some JSON, using optional conditions with where clauses.

guard
    let fileContents = fileContents,
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as? NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray where featuresArray.count > 0,
    let featuresDict = featuresArray[0] as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"] where coordinatesArray.count > 0,
    let coordinateArray = coordinatesArray[0] as? NSArray where coordinateArray.count > 3
    else { fatalError("Reason") }

Each `where` test is a separate test. While there are semantic ties between the conditional binding and the count tests, there doesn't have to be. Under Swift's current rules, you must use the `where` keyword to introduce a Boolean test after a binding or pattern, regardless of whether or not there's an underlying semantic link between the two.

By removing this requirement and allowing interchangeability between `where` and `,`, you're given the option of tying the boolean to the binding/pattern match or introducing a boolean statement with no connection to previous steps. Here's what this example looks like after excluding `where`:

guard
    let fileContents = fileContents,
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as? NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray,
    featuresArray.count > 0,
    let featuresDict = featuresArray.firstObject as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"],
    coordinatesArray.count > 0,
    let coordinateArray = coordinatesArray.firstObject as? NSArray,
    coordinateArray.count > 3
    else { fatalError("Reason") }

I have mixed thoughts about it. The former perl swchartzian-transform fan loves it, and the more responsible high speed trading systems developer finds it the kind of look-it-works-without-the-hands code i am not typically eager to see people do in my teams.
The apache spark project is a great example of a widely popular scala project that succeeded because it banned the kind of back-breaking areobatics that compilers can make sense of and normal (i.e not overly expensive and reasonably productive) developers typically get tangled in.

···

On May 20, 2016, at 7:07 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

The motivation for this approach becomes more compelling when the Boolean tests are disjoint from binding or pattern matches.

guard
    minimumShapeCount > 4,
    let shapes = decompose(map, minimum: minimumShapeCount),
    availableArea > minimumArea,
    let map = placeShapes(shapes, availableArea) else {
        fatalError()
}

would be allowed compared to current Swift which mandates where between the second and third tests:

    let shapes = decompose(map, minimum: minimumShapeCount) where availableArea > minimumArea,

In my vision, Swift would continue to allow where clauses and expand to allow disjoint Boolean entries.

Thoughts?

-- E

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


(Krystof Vasa) #5

+1 for me. Been longing for something like this myself this actually.

···

On May 20, 2016, at 7:07 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

Earlier on Swift Evolution:

Me: "Is there a technical reason that Swift cannot be expanded to allow arbitrary mixes of conditional binding and boolean assertions within a single compound guard statement?"

Joe Groff: "No. You already can, we just have the somewhat strange rule that to separate `guard` conditions uses `,` before optional or pattern conditions, but `where` before Boolean conditions. There's no technical reason we couldn't accept either 'where' or ',' consistently."

  guard x == 0,
    let y = optional where
    z == 2 {
  }

Pitch:

I'd like to update Swift's grammar to interchangeably and consistently accept `where` or `,` to separate guard conditions. This would allow a more consistent approach that supports intermingling conditional binding and boolean assertions. Here's a real-world bit of code I was helping someone with a few evenings ago. It's attempting to navigate through some JSON, using optional conditions with where clauses.

guard
    let fileContents = fileContents,
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as? NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray where featuresArray.count > 0,
    let featuresDict = featuresArray[0] as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"] where coordinatesArray.count > 0,
    let coordinateArray = coordinatesArray[0] as? NSArray where coordinateArray.count > 3
    else { fatalError("Reason") }

Each `where` test is a separate test. While there are semantic ties between the conditional binding and the count tests, there doesn't have to be. Under Swift's current rules, you must use the `where` keyword to introduce a Boolean test after a binding or pattern, regardless of whether or not there's an underlying semantic link between the two.

By removing this requirement and allowing interchangeability between `where` and `,`, you're given the option of tying the boolean to the binding/pattern match or introducing a boolean statement with no connection to previous steps. Here's what this example looks like after excluding `where`:

guard
    let fileContents = fileContents,
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as? NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray,
    featuresArray.count > 0,
    let featuresDict = featuresArray.firstObject as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"],
    coordinatesArray.count > 0,
    let coordinateArray = coordinatesArray.firstObject as? NSArray,
    coordinateArray.count > 3
    else { fatalError("Reason") }

The motivation for this approach becomes more compelling when the Boolean tests are disjoint from binding or pattern matches.

guard
    minimumShapeCount > 4,
    let shapes = decompose(map, minimum: minimumShapeCount),
    availableArea > minimumArea,
    let map = placeShapes(shapes, availableArea) else {
        fatalError()
}

would be allowed compared to current Swift which mandates where between the second and third tests:

    let shapes = decompose(map, minimum: minimumShapeCount) where availableArea > minimumArea,

In my vision, Swift would continue to allow where clauses and expand to allow disjoint Boolean entries.

Thoughts?

-- E

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


(Austin Zheng) #6

I like the idea in principle.

However, right now you can write something like:

if let a = optionalA, frob = fooBarBaz() { ... }

It's clear that both clauses are optional binding clauses.

With this change, it's not clear anymore whether the second clause is an
optional binding clause, or a logic test erroneously using '=' instead of
'=='.

To be fair, though, since assignment in Swift doesn't return the new value
as it does in C, there is far less room for disastrous bugs caused by this
sort of mistake.

Austin

···

On Fri, May 20, 2016 at 10:07 AM, Erica Sadun via swift-evolution < swift-evolution@swift.org> wrote:

*Earlier on Swift Evolution:*

Me: "*Is there a technical reason that Swift cannot be expanded to allow
arbitrary mixes of conditional binding and boolean assertions within a
single compound guard statement?*"

Joe Groff: "*No. You already can, we just have the somewhat strange rule
that to separate `guard` conditions uses `,` before optional or pattern
conditions, but `where` before Boolean conditions. **There's no technical
reason we couldn't accept either 'where' or ',' consistently."*

guard x == 0,
let y = optional where
z == 2 {
}

*Pitch: *

I'd like to update Swift's grammar to interchangeably and consistently
accept `where` or `,` to separate guard conditions. This would allow a more
consistent approach that supports intermingling conditional binding and
boolean assertions. Here's a real-world bit of code I was helping someone
with a few evenings ago. It's attempting to navigate through some JSON,
using optional conditions with where clauses.

guard
    let fileContents = fileContents,
    let jsonDict = try
NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as?
NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray *where **featuresArray.count
> 0,*
    let featuresDict = featuresArray[0] as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"] *where **coordinatesArray.count
> 0,*
    let coordinateArray = coordinatesArray[0] as? NSArray *where **coordinateArray.count
> 3*
    else { fatalError("Reason") }

Each `where` test is a separate test. While there *are* semantic ties
between the conditional binding and the count tests, there *doesn't have
to be*. Under Swift's current rules, you must use the `where` keyword to
introduce a Boolean test after a binding or pattern, regardless of whether
or not there's an underlying semantic link between the two.

By removing this requirement and allowing interchangeability between
`where` and `,`, you're given the option of tying the boolean to the
binding/pattern match or introducing a boolean statement with no connection
to previous steps. Here's what this example looks like after excluding
`where`:

guard
    let fileContents = fileContents,
    let jsonDict = try
NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as?
NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray,
* featuresArray.count > 0,*
    let featuresDict = featuresArray.firstObject as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"],
* coordinatesArray.count > 0,*
    let coordinateArray = coordinatesArray.firstObject as? NSArray,
    *coordinateArray.count > 3*
    else { fatalError("Reason") }

The motivation for this approach becomes more compelling when the Boolean
tests are disjoint from binding or pattern matches.

guard
    minimumShapeCount > 4,
    let shapes = decompose(map, minimum: minimumShapeCount),
    availableArea > minimumArea,
    let map = placeShapes(shapes, availableArea) else {
        fatalError()
}

would be allowed compared to current Swift which mandates where between
the second and third tests:

    let shapes = decompose(map, minimum: minimumShapeCount) where availableArea
> minimumArea,

In my vision, Swift would continue to allow where clauses and expand to
allow disjoint Boolean entries.

Thoughts?

-- E

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


(Erica Sadun) #7

That's kind of the heart of the matter.

There's an assumption that guard statements are:

`guard` (conjoined boolean tests) | (conjoined boolean tests,)? (pattern | binding (where boolean)?, )+ else {...}

Right? (Except I couldn't figure out how to grammar out the final comma,) I'm suggesting:

`guard` ((boolean | (pattern | binding (where boolean)?)),)+ else {...}

instead. (And ditto about final comma) This promotes boolean statements to the same standing, so they're not limited to the start of the guard statement or syntactically tied to a pattern/binding where there may be no semantic basis.

-- E

···

On May 20, 2016, at 11:53 AM, Matthew Johnson <matthew@anandabits.com> wrote:
I am less certain about allowing simple boolean expressions that are not introduced by the `where` keyword (excepting the first one which is introduced with the `guard` keyword). I think this is a separate question that should receive independent consideration. I think a reasonable argument can be made both ways.


(Matthew Johnson) #8

I am less certain about allowing simple boolean expressions that are not introduced by the `where` keyword (excepting the first one which is introduced with the `guard` keyword). I think this is a separate question that should receive independent consideration. I think a reasonable argument can be made both ways.

That's kind of the heart of the matter.

There's an assumption that guard statements are:

`guard` (conjoined boolean tests) | (conjoined boolean tests,)? (pattern | binding (where boolean)?, )+ else {...}

Right? (Except I couldn't figure out how to grammar out the final comma,) I'm suggesting:

`guard` ((boolean | (pattern | binding (where boolean)?)),)+ else {...}

instead. (And ditto about final comma) This promotes boolean statements to the same standing, so they're not limited to the start of the guard statement or syntactically tied to a pattern/binding where there may be no semantic basis.

Yep, I know. I’m agreeing with breaking the syntactic tie to pattern binding, just questioning whether we should drop the need to introduce subsequent ones with `where`. I am on the fence as to which is more readable and interested in hearing discussion about that.

This is what it would look like if drop the requirement that they be tied to a pattern binding but we require `where` on subsequent boolean expressions (meaning each clause is introduced with a keyword.

`guard` (boolean,)? (((where boolean) | (pattern | binding (where boolean)?)),)+ else {…}

We could also do this if we wanted to allow all boolean expressions, even the first, to be introduced with `where` to support consistent formatting of all clauses in a multi-line construct like the ones in your example.

`guard` (where? boolean,)? (((where boolean) | (pattern | binding (where boolean)?)),)+ else {...}

···

On May 20, 2016, at 1:01 PM, Erica Sadun <erica@ericasadun.com> wrote:

On May 20, 2016, at 11:53 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

-- E


(L Mihalkovic) #9

I am less certain about allowing simple boolean expressions that are not introduced by the `where` keyword (excepting the first one which is introduced with the `guard` keyword). I think this is a separate question that should receive independent consideration. I think a reasonable argument can be made both ways.

That's kind of the heart of the matter.

There's an assumption that guard statements are:

`guard` (conjoined boolean tests) | (conjoined boolean tests,)? (pattern | binding (where boolean)?, )+ else {...}

Right? (Except I couldn't figure out how to grammar out the final comma,) I'm suggesting:

`guard` ((boolean | (pattern | binding (where boolean)?)),)+ else {...}

instead. (And ditto about final comma) This promotes boolean statements to the same standing, so they're not limited to the start of the guard statement or syntactically tied to a pattern/binding where there may be no semantic basis.

-- E

GRAMMAR OF A GUARD STATEMENT

<>guard-statement → guard­condition-clause <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/condition-clause>­else­code-block <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block
<>condition-clause → expression <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression
<>condition-clause → expression <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression>­,­condition-list <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/condition-list
<>condition-clause → condition-list <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/condition-list
<>condition-clause → availability-condition <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/availability-condition>­,­expression <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression
<>condition-list → condition <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/condition>­ condition <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/condition>­,­condition-list <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/condition-list
<>condition → availability-condition <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/availability-condition>­ case-condition <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-condition>­ optional-binding-condition <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/optional-binding-condition
<>case-condition → case­pattern <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern>­initializer <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/initializer>­where-clause <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/where-clause>­opt­

it is all shared at the moment.

/// stmt-guard:
/// 'guard' condition 'else' stmt-brace
///
ParserResult<Stmt> Parser::parseStmtGuard() {
  SourceLoc GuardLoc = consumeToken(tok::kw_guard);
  
...

I guess it means that stepping out of what it currently does is straightforward to isolate from side effects, but likely a significant piece of work if it is not make a superset (meaning that bits and parts or the way the current grammar is structured can be reused in the manner they are today) of what it is today.

···

On May 20, 2016, at 8:01 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On May 20, 2016, at 11:53 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

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


(Erica Sadun) #10

Right now, if you look at the grammar, it's pretty hard to follow and special cased.
I think if people follow an intentional pattern of a condition per line (including where clauses)
they won't get in trouble. (Also Swift is a lot smarter about inadvertent = vs ==)

-- E

···

On May 24, 2016, at 11:59 AM, Austin Zheng <austinzheng@gmail.com> wrote:

I like the idea in principle.

However, right now you can write something like:

if let a = optionalA, frob = fooBarBaz() { ... }

It's clear that both clauses are optional binding clauses.

With this change, it's not clear anymore whether the second clause is an optional binding clause, or a logic test erroneously using '=' instead of '=='.

To be fair, though, since assignment in Swift doesn't return the new value as it does in C, there is far less room for disastrous bugs caused by this sort of mistake.

Austin


(Erica Sadun) #11

Okay, and here is where the problem is (thanks Chris L)

`z = q` is an expression. It returns Void.

For example:

let q = 5
var z = 0
let foo = z = q // foo inferred to have type `()` which may be unexpected

So if you have the following statement:

guard let x = optional, z = q else {...}

where q is non-optional, there's issues in that `q` is not an optional and `z = q` is an expression.

-- E

···

On May 24, 2016, at 11:59 AM, Austin Zheng <austinzheng@gmail.com> wrote:

I like the idea in principle.

However, right now you can write something like:

if let a = optionalA, frob = fooBarBaz() { ... }

It's clear that both clauses are optional binding clauses.

With this change, it's not clear anymore whether the second clause is an optional binding clause, or a logic test erroneously using '=' instead of '=='.

To be fair, though, since assignment in Swift doesn't return the new value as it does in C, there is far less room for disastrous bugs caused by this sort of mistake.

Austin

On Fri, May 20, 2016 at 10:07 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Earlier on Swift Evolution:

Me: "Is there a technical reason that Swift cannot be expanded to allow arbitrary mixes of conditional binding and boolean assertions within a single compound guard statement?"

Joe Groff: "No. You already can, we just have the somewhat strange rule that to separate `guard` conditions uses `,` before optional or pattern conditions, but `where` before Boolean conditions. There's no technical reason we couldn't accept either 'where' or ',' consistently."

  guard x == 0,
    let y = optional where
    z == 2 {
  }

Pitch:

I'd like to update Swift's grammar to interchangeably and consistently accept `where` or `,` to separate guard conditions. This would allow a more consistent approach that supports intermingling conditional binding and boolean assertions. Here's a real-world bit of code I was helping someone with a few evenings ago. It's attempting to navigate through some JSON, using optional conditions with where clauses.

guard
    let fileContents = fileContents,
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as? NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray where featuresArray.count > 0,
    let featuresDict = featuresArray[0] as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"] where coordinatesArray.count > 0,
    let coordinateArray = coordinatesArray[0] as? NSArray where coordinateArray.count > 3
    else { fatalError("Reason") }

Each `where` test is a separate test. While there are semantic ties between the conditional binding and the count tests, there doesn't have to be. Under Swift's current rules, you must use the `where` keyword to introduce a Boolean test after a binding or pattern, regardless of whether or not there's an underlying semantic link between the two.

By removing this requirement and allowing interchangeability between `where` and `,`, you're given the option of tying the boolean to the binding/pattern match or introducing a boolean statement with no connection to previous steps. Here's what this example looks like after excluding `where`:

guard
    let fileContents = fileContents,
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as? NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray,
    featuresArray.count > 0,
    let featuresDict = featuresArray.firstObject as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"],
    coordinatesArray.count > 0,
    let coordinateArray = coordinatesArray.firstObject as? NSArray,
    coordinateArray.count > 3
    else { fatalError("Reason") }

The motivation for this approach becomes more compelling when the Boolean tests are disjoint from binding or pattern matches.

guard
    minimumShapeCount > 4,
    let shapes = decompose(map, minimum: minimumShapeCount),
    availableArea > minimumArea,
    let map = placeShapes(shapes, availableArea) else {
        fatalError()
}

would be allowed compared to current Swift which mandates where between the second and third tests:

    let shapes = decompose(map, minimum: minimumShapeCount) where availableArea > minimumArea,

In my vision, Swift would continue to allow where clauses and expand to allow disjoint Boolean entries.

Thoughts?

-- E

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


(Erica Sadun) #12

GRAMMAR OF A GUARD STATEMENT

<>guard-statement → guard­condition-clause <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/condition-clause>­else­code-block <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block
<>condition-clause → expression <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression
<>condition-clause → expression <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression>­,­condition-list <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/condition-list
<>condition-clause → condition-list <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/condition-list
<>condition-clause → availability-condition <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/availability-condition>­,­expression <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression
<>condition-list → condition <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/condition>­ condition <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/condition>­,­condition-list <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/condition-list
<>condition → availability-condition <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/availability-condition>­ case-condition <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-condition>­ optional-binding-condition <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/optional-binding-condition
<>case-condition → case­pattern <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern>­initializer <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/initializer>­where-clause <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/where-clause>­opt­

While the easiest solution allows commas interchangeably with `where`, it would allow construction of statements like this and
it wouldn't introduce the ability to mix and match Boolean expressions, availability conditions, case conditions, and optional binding conditions.

// where-clause → (where | ,) where-expression
for i in 0...10, i % 2 == 0 { print(i) }

To get that you need:

‌condition-list → condition | expression | condition , condition-list | expression, condition-list

Which means that `guard` would be redefined to:

guard condition-list else code-block

This would affect `while`, `repeat-while`, `if`, and `guard`.

-- E


(Jacob Bandes-Storch) #13

Could we just require "let" (or var) to introduce every binding, rather
than allowing the combination "if let x = y, z = q, ..."? I always use
"let" anyway; I think it's easier to read.

···

On Tue, May 24, 2016 at 11:42 AM, Erica Sadun via swift-evolution < swift-evolution@swift.org> wrote:

Okay, and here is where the problem is (thanks Chris L)

`z = q` is an expression. It returns Void.

For example:

let q = 5
var z = 0
let foo = z = q // foo inferred to have type `()` which may be unexpected

So if you have the following statement:

guard let x = optional, z = q else {...}

where q is non-optional, there's issues in that `q` is not an optional and
`z = q` is an expression.

-- E

On May 24, 2016, at 11:59 AM, Austin Zheng <austinzheng@gmail.com> wrote:

I like the idea in principle.

However, right now you can write something like:

if let a = optionalA, frob = fooBarBaz() { ... }

It's clear that both clauses are optional binding clauses.

With this change, it's not clear anymore whether the second clause is an
optional binding clause, or a logic test erroneously using '=' instead of
'=='.

To be fair, though, since assignment in Swift doesn't return the new value
as it does in C, there is far less room for disastrous bugs caused by this
sort of mistake.

Austin

On Fri, May 20, 2016 at 10:07 AM, Erica Sadun via swift-evolution < > swift-evolution@swift.org> wrote:

*Earlier on Swift Evolution:*

Me: "*Is there a technical reason that Swift cannot be expanded to allow
arbitrary mixes of conditional binding and boolean assertions within a
single compound guard statement?*"

Joe Groff: "*No. You already can, we just have the somewhat strange rule
that to separate `guard` conditions uses `,` before optional or pattern
conditions, but `where` before Boolean conditions. **There's no
technical reason we couldn't accept either 'where' or ',' consistently."*

guard x == 0,
let y = optional where
z == 2 {
}

*Pitch: *

I'd like to update Swift's grammar to interchangeably and consistently
accept `where` or `,` to separate guard conditions. This would allow a more
consistent approach that supports intermingling conditional binding and
boolean assertions. Here's a real-world bit of code I was helping someone
with a few evenings ago. It's attempting to navigate through some JSON,
using optional conditions with where clauses.

guard
    let fileContents = fileContents,
    let jsonDict = try
NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as?
NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray *where **featuresArray.count
> 0,*
    let featuresDict = featuresArray[0] as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"] *where **coordinatesArray.count
> 0,*
    let coordinateArray = coordinatesArray[0] as? NSArray *where **coordinateArray.count
> 3*
    else { fatalError("Reason") }

Each `where` test is a separate test. While there *are* semantic ties
between the conditional binding and the count tests, there *doesn't have
to be*. Under Swift's current rules, you must use the `where` keyword
to introduce a Boolean test after a binding or pattern, regardless of
whether or not there's an underlying semantic link between the two.

By removing this requirement and allowing interchangeability between
`where` and `,`, you're given the option of tying the boolean to the
binding/pattern match or introducing a boolean statement with no connection
to previous steps. Here's what this example looks like after excluding
`where`:

guard
    let fileContents = fileContents,
    let jsonDict = try
NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as?
NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray,
* featuresArray.count > 0,*
    let featuresDict = featuresArray.firstObject as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"],
* coordinatesArray.count > 0,*
    let coordinateArray = coordinatesArray.firstObject as? NSArray,
    *coordinateArray.count > 3*
    else { fatalError("Reason") }

The motivation for this approach becomes more compelling when the Boolean
tests are disjoint from binding or pattern matches.

guard
    minimumShapeCount > 4,
    let shapes = decompose(map, minimum: minimumShapeCount),
    availableArea > minimumArea,
    let map = placeShapes(shapes, availableArea) else {
        fatalError()
}

would be allowed compared to current Swift which mandates where between
the second and third tests:

    let shapes = decompose(map, minimum: minimumShapeCount) where availableArea
> minimumArea,

In my vision, Swift would continue to allow where clauses and expand to
allow disjoint Boolean entries.

Thoughts?

-- E

_______________________________________________
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


(Erica Sadun) #14

Or you can make sure every expression is boolean, which would take care of this as well...

-- E

···

On May 24, 2016, at 12:47 PM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

Could we just require "let" (or var) to introduce every binding, rather than allowing the combination "if let x = y, z = q, ..."? I always use "let" anyway; I think it's easier to read.

On Tue, May 24, 2016 at 11:42 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Okay, and here is where the problem is (thanks Chris L)

`z = q` is an expression. It returns Void.

For example:

let q = 5
var z = 0
let foo = z = q // foo inferred to have type `()` which may be unexpected

So if you have the following statement:

guard let x = optional, z = q else {...}

where q is non-optional, there's issues in that `q` is not an optional and `z = q` is an expression.

-- E

On May 24, 2016, at 11:59 AM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

I like the idea in principle.

However, right now you can write something like:

if let a = optionalA, frob = fooBarBaz() { ... }

It's clear that both clauses are optional binding clauses.

With this change, it's not clear anymore whether the second clause is an optional binding clause, or a logic test erroneously using '=' instead of '=='.

To be fair, though, since assignment in Swift doesn't return the new value as it does in C, there is far less room for disastrous bugs caused by this sort of mistake.

Austin

On Fri, May 20, 2016 at 10:07 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Earlier on Swift Evolution:

Me: "Is there a technical reason that Swift cannot be expanded to allow arbitrary mixes of conditional binding and boolean assertions within a single compound guard statement?"

Joe Groff: "No. You already can, we just have the somewhat strange rule that to separate `guard` conditions uses `,` before optional or pattern conditions, but `where` before Boolean conditions. There's no technical reason we couldn't accept either 'where' or ',' consistently."

  guard x == 0,
    let y = optional where
    z == 2 {
  }

Pitch:

I'd like to update Swift's grammar to interchangeably and consistently accept `where` or `,` to separate guard conditions. This would allow a more consistent approach that supports intermingling conditional binding and boolean assertions. Here's a real-world bit of code I was helping someone with a few evenings ago. It's attempting to navigate through some JSON, using optional conditions with where clauses.

guard
    let fileContents = fileContents,
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as? NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray where featuresArray.count > 0,
    let featuresDict = featuresArray[0] as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"] where coordinatesArray.count > 0,
    let coordinateArray = coordinatesArray[0] as? NSArray where coordinateArray.count > 3
    else { fatalError("Reason") }

Each `where` test is a separate test. While there are semantic ties between the conditional binding and the count tests, there doesn't have to be. Under Swift's current rules, you must use the `where` keyword to introduce a Boolean test after a binding or pattern, regardless of whether or not there's an underlying semantic link between the two.

By removing this requirement and allowing interchangeability between `where` and `,`, you're given the option of tying the boolean to the binding/pattern match or introducing a boolean statement with no connection to previous steps. Here's what this example looks like after excluding `where`:

guard
    let fileContents = fileContents,
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(fileContents, options: []) as? NSDictionary,
    let featuresArray = jsonDict["features"] as? NSArray,
    featuresArray.count > 0,
    let featuresDict = featuresArray.firstObject as? NSDictionary,
    let coordinatesArray = featuresDict["geometry"],
    coordinatesArray.count > 0,
    let coordinateArray = coordinatesArray.firstObject as? NSArray,
    coordinateArray.count > 3
    else { fatalError("Reason") }

The motivation for this approach becomes more compelling when the Boolean tests are disjoint from binding or pattern matches.

guard
    minimumShapeCount > 4,
    let shapes = decompose(map, minimum: minimumShapeCount),
    availableArea > minimumArea,
    let map = placeShapes(shapes, availableArea) else {
        fatalError()
}

would be allowed compared to current Swift which mandates where between the second and third tests:

    let shapes = decompose(map, minimum: minimumShapeCount) where availableArea > minimumArea,

In my vision, Swift would continue to allow where clauses and expand to allow disjoint Boolean entries.

Thoughts?

-- E

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

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


(Erica Sadun) #15

Draft: https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160

Simplifying condition clauses and intermingling expressions with other conditions

Proposal: TBD
Author: Erica Sadun <https://github.com/erica>
Status: TBD
Review manager: TBD
<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#introduction>Introduction

This proposal adjust Swift grammar to enable the arbitrary mix of expressions among conditions rather than constraining them before other conditions. Under this proposal, expressions are no longer limited to where clauses after the initial list of Boolean conditions.

Swift-evolution thread: [Pitch] making where and , interchangeable in guard conditions <http://thread.gmane.org/gmane.comp.lang.swift.evolution/17926>
<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#motivation>Motivation

There is no technical reason to disallow arbitrary mixes of binding, patterns, availability tests, and Boolean assertions within a single compound condition clause. Swift currently enforces a grammar that limits expressions to where clauses after the first non-Boolean condition clause has been mentioned. This rule means that all standalone Boolean tests must precede binding and pattern conditions and allows for code such as:

guard
    x == 0,
    let y = optional where z == 2
    else { ... }
In this example, the Boolean z == 2 clause has no semantic relationship to the optional condition to which it's syntactically bound. Ideally, where clauses should be restricted to a Boolean assertion tied to variables connected to the binding or pattern condition. Unrelated Boolean assertions should be allowed to stand on their own

If accepted, the following code would be legal, as would similar usage in while and if statements.

guard
    x == 0,
    let y = optional,
    z == 2
    else { ... }
<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#detailed-design>Detailed Design

Under this proposal, condition lists are updated to accept a grammar along the following lines:

‌condition-list → condition | expression | condition , condition-list | expression, condition-list
This enables guard, while, repeat-while, and if to adopt grammars like:

guard condition-list else code-block
while condition-list code-block
if condition-list code-block (else-clause)?
Note: A repeat-while statement does not use a condition list. Its grammar is repeat code-block while expression

This approach simplifies the current Swift grammar, which constructs condition clauses separately from condition lists and conditions. This extra work is needed to introduce an expression before condition lists and to allow an expression after availability checks:

condition-clause → expression
condition-clause → expression , condition-list
condition-clause → condition-list
condition-clause → availability-condition , expression
condition-list → condition | condition,condition-list
condition → availability-condition | case-condition | optional-binding-condition
Beyond this high level change, all three conditions (availability conditions, case conditions, and optional binding conditions) remain unaffected as do their associated where clause grammar. This solution changes list construction not whereclauses.

<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#impact-on-existing-code>Impact on Existing Code

This proposal does not affect existing code.

<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#alternatives-considered>Alternatives Considered

The "easiest" solution that free interchange of commas with where, permits construction of statements like the following:

// where-clause → (where | ,) where-expression
for i in 0...10, i % 2 == 0 { print(i) }
Adjusting the where clause in this way wouldn't introduce the ability to mix and match Boolean expressions, availability conditions, case conditions, and optional binding conditions in condition clauses, and is therefore discarded from consideration.


(Xiaodi Wu) #16

Does this proposal distinguish between "where clauses [...] restricted to a
Boolean assertion tied to variables connected to the binding or pattern
condition" and "unrelated Boolean assertions [that] should be allowed to
stand on their own"?

Or are both types of boolean assertions now permitted either following a
comma or following a where clause?

···

On Tue, May 24, 2016 at 10:10 Erica Sadun via swift-evolution < swift-evolution@swift.org> wrote:

Draft: https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160

Simplifying condition clauses and intermingling expressions with other
conditions

   - Proposal: TBD
   - Author: Erica Sadun <https://github.com/erica>
   - Status: TBD
   - Review manager: TBD

<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#introduction>
Introduction

This proposal adjust Swift grammar to enable the arbitrary mix of
expressions among conditions rather than constraining them before other
conditions. Under this proposal, expressions are no longer limited to where
clauses after the initial list of Boolean conditions.

Swift-evolution thread: [Pitch] making where and , interchangeable in
guard conditions
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/17926>
<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#motivation>
Motivation

There is no technical reason to disallow arbitrary mixes of binding,
patterns, availability tests, and Boolean assertions within a single
compound condition clause. Swift currently enforces a grammar that limits
expressions to where clauses after the first non-Boolean condition clause
has been mentioned. This rule means that all standalone Boolean tests must
precede binding and pattern conditions and allows for code such as:

guard
    x == 0,
    let y = optional where z == 2

    else { ... }

In this example, the Boolean z == 2 clause has no semantic relationship
to the optional condition to which it's syntactically bound. Ideally,
where clauses should be restricted to a Boolean assertion tied to
variables connected to the binding or pattern condition. Unrelated Boolean
assertions should be allowed to stand on their own

If accepted, the following code would be legal, as would similar usage in
while and if statements.

guard
    x == 0,
    let y = optional,
    z == 2
    else { ... }

<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#detailed-design>Detailed
Design

Under this proposal, condition lists are updated to accept a grammar along
the following lines:

‌condition-list → condition | expression | condition , condition-list | expression, condition-list

This enables guard, while, repeat-while, and if to adopt grammars like:

guard condition-list else code-block
while condition-list code-block
if condition-list code-block (else-clause)?

*Note: A repeat-while statement does not use a condition list. Its grammar
is repeat code-block while expression*

This approach simplifies the current Swift grammar, which constructs
condition clauses separately from condition lists and conditions. This
extra work is needed to introduce an expression before condition lists and
to allow an expression after availability checks:

condition-clause → expression
condition-clause → expression , condition-list
condition-clause → condition-list
condition-clause → availability-condition , expression
condition-list → condition | condition,condition-list
condition → availability-condition | case-condition | optional-binding-condition

Beyond this high level change, all three conditions (availability
conditions, case conditions, and optional binding conditions) remain
unaffected as do their associated where clause grammar. This solution
changes list construction not whereclauses.

<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#impact-on-existing-code>Impact
on Existing Code

This proposal does not affect existing code.

<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#alternatives-considered>Alternatives
Considered

The "easiest" solution that free interchange of commas with where,
permits construction of statements like the following:

// where-clause → (where | ,) where-expressionfor i in 0...10, i % 2 == 0 { print(i) }

Adjusting the where clause in this way wouldn't introduce the ability to
mix and match Boolean expressions, availability conditions, case
conditions, and optional binding conditions in condition clauses, and is
therefore discarded from consideration.

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


(Erica Sadun) #17

There is no way I could figure out how to restrict Boolean assertions to mentioned variables therefore I left where clauses entirely untouched.
I'd recommend people adopt in-house standards where Boolean assertions in where clauses should be semantically tied to the condition
clause that introduces them.

I will add this as a note.

-- E

···

On May 24, 2016, at 9:29 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Does this proposal distinguish between "where clauses [...] restricted to a Boolean assertion tied to variables connected to the binding or pattern condition" and "unrelated Boolean assertions [that] should be allowed to stand on their own"?

Or are both types of boolean assertions now permitted either following a comma or following a where clause?

On Tue, May 24, 2016 at 10:10 Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Draft: https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160

Simplifying condition clauses and intermingling expressions with other conditions

Proposal: TBD
Author: Erica Sadun <https://github.com/erica>
Status: TBD
Review manager: TBD
<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#introduction>Introduction

This proposal adjust Swift grammar to enable the arbitrary mix of expressions among conditions rather than constraining them before other conditions. Under this proposal, expressions are no longer limited to where clauses after the initial list of Boolean conditions.

Swift-evolution thread: [Pitch] making where and , interchangeable in guard conditions <http://thread.gmane.org/gmane.comp.lang.swift.evolution/17926>
<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#motivation>Motivation

There is no technical reason to disallow arbitrary mixes of binding, patterns, availability tests, and Boolean assertions within a single compound condition clause. Swift currently enforces a grammar that limits expressions to where clauses after the first non-Boolean condition clause has been mentioned. This rule means that all standalone Boolean tests must precede binding and pattern conditions and allows for code such as:

guard
    x == 0,
    let y = optional where z == 2

    else { ... }
In this example, the Boolean z == 2 clause has no semantic relationship to the optional condition to which it's syntactically bound. Ideally, where clauses should be restricted to a Boolean assertion tied to variables connected to the binding or pattern condition. Unrelated Boolean assertions should be allowed to stand on their own

If accepted, the following code would be legal, as would similar usage in while and if statements.

guard
    x == 0,
    let y = optional,
    z == 2
    else { ... }
<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#detailed-design>Detailed Design

Under this proposal, condition lists are updated to accept a grammar along the following lines:

‌condition-list → condition | expression | condition , condition-list | expression, condition-list
This enables guard, while, repeat-while, and if to adopt grammars like:

guard condition-list else code-block
while condition-list code-block
if condition-list code-block (else-clause)?
Note: A repeat-while statement does not use a condition list. Its grammar is repeat code-block while expression

This approach simplifies the current Swift grammar, which constructs condition clauses separately from condition lists and conditions. This extra work is needed to introduce an expression before condition lists and to allow an expression after availability checks:

condition-clause → expression
condition-clause → expression , condition-list
condition-clause → condition-list
condition-clause → availability-condition , expression
condition-list → condition | condition,condition-list
condition → availability-condition | case-condition | optional-binding-condition
Beyond this high level change, all three conditions (availability conditions, case conditions, and optional binding conditions) remain unaffected as do their associated where clause grammar. This solution changes list construction not whereclauses.

<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#impact-on-existing-code>Impact on Existing Code

This proposal does not affect existing code.

<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#alternatives-considered>Alternatives Considered

The "easiest" solution that free interchange of commas with where, permits construction of statements like the following:

// where-clause → (where | ,) where-expression
for i in 0...10, i % 2 == 0 { print(i) }
Adjusting the where clause in this way wouldn't introduce the ability to mix and match Boolean expressions, availability conditions, case conditions, and optional binding conditions in condition clauses, and is therefore discarded from consideration.

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


(Xiaodi Wu) #18

With the implementation of your proposal, will there be anything that can
be written in where clauses that cannot be written after a comma (in the
context of guard statements specifically)? If not, does the where clause
become entirely a stylistic flourish?

···

On Tue, May 24, 2016 at 11:57 Erica Sadun <erica@ericasadun.com> wrote:

There is no way I could figure out how to restrict Boolean assertions to
mentioned variables therefore I left where clauses entirely untouched.
I'd recommend people adopt in-house standards where Boolean assertions in
where clauses should be semantically tied to the condition
clause that introduces them.

I will add this as a note.

-- E

On May 24, 2016, at 9:29 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Does this proposal distinguish between "where clauses [...] restricted to
a Boolean assertion tied to variables connected to the binding or pattern
condition" and "unrelated Boolean assertions [that] should be allowed to
stand on their own"?

Or are both types of boolean assertions now permitted either following a
comma or following a where clause?

On Tue, May 24, 2016 at 10:10 Erica Sadun via swift-evolution < > swift-evolution@swift.org> wrote:

Draft: https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160

Simplifying condition clauses and intermingling expressions with other
conditions

   - Proposal: TBD
   - Author: Erica Sadun <https://github.com/erica>
   - Status: TBD
   - Review manager: TBD

<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#introduction>
Introduction

This proposal adjust Swift grammar to enable the arbitrary mix of
expressions among conditions rather than constraining them before other
conditions. Under this proposal, expressions are no longer limited to where
clauses after the initial list of Boolean conditions.

Swift-evolution thread: [Pitch] making where and , interchangeable in
guard conditions
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/17926>

<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#motivation>
Motivation

There is no technical reason to disallow arbitrary mixes of binding,
patterns, availability tests, and Boolean assertions within a single
compound condition clause. Swift currently enforces a grammar that limits
expressions to where clauses after the first non-Boolean condition
clause has been mentioned. This rule means that all standalone Boolean
tests must precede binding and pattern conditions and allows for code such
as:

guard
    x == 0,
    let y = optional where z == 2

    else { ... }

In this example, the Boolean z == 2 clause has no semantic relationship
to the optional condition to which it's syntactically bound. Ideally,
where clauses should be restricted to a Boolean assertion tied to
variables connected to the binding or pattern condition. Unrelated Boolean
assertions should be allowed to stand on their own

If accepted, the following code would be legal, as would similar usage in
while and if statements.

guard
    x == 0,
    let y = optional,
    z == 2
    else { ... }

<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#detailed-design>Detailed
Design

Under this proposal, condition lists are updated to accept a grammar
along the following lines:

‌condition-list → condition | expression | condition , condition-list | expression, condition-list

This enables guard, while, repeat-while, and if to adopt grammars like:

guard condition-list else code-block
while condition-list code-block
if condition-list code-block (else-clause)?

*Note: A repeat-while statement does not use a condition list. Its
grammar is repeat code-block while expression*

This approach simplifies the current Swift grammar, which constructs
condition clauses separately from condition lists and conditions. This
extra work is needed to introduce an expression before condition lists and
to allow an expression after availability checks:

condition-clause → expression
condition-clause → expression , condition-list
condition-clause → condition-list
condition-clause → availability-condition , expression
condition-list → condition | condition,condition-list
condition → availability-condition | case-condition | optional-binding-condition

Beyond this high level change, all three conditions (availability
conditions, case conditions, and optional binding conditions) remain
unaffected as do their associated where clause grammar. This solution
changes list construction not whereclauses.

<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#impact-on-existing-code>Impact
on Existing Code

This proposal does not affect existing code.

<https://gist.github.com/erica/74cfee56a597c0e0026a90ee4e49f160#alternatives-considered>Alternatives
Considered

The "easiest" solution that free interchange of commas with where,
permits construction of statements like the following:

// where-clause → (where | ,) where-expressionfor i in 0...10, i % 2 == 0 { print(i) }

Adjusting the where clause in this way wouldn't introduce the ability to
mix and match Boolean expressions, availability conditions, case
conditions, and optional binding conditions in condition clauses, and is
therefore discarded from consideration.

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


(Joe Groff) #19

The where clause is not a stylistic flourish because it is still best used to constrain conditions that are semantically
related to conditions. Upon acceptance as now, there are no compiler checks that mandate any relationship.

From a semantic perspective, at least, 'where' and ',' don't really matter to the compiler. Either one is an "and" composition of the list conditions.

-Joe

···

On May 24, 2016, at 10:07 AM, Erica Sadun <erica@ericasadun.com> wrote:

The difference is that (1) coders will be allowed to move Boolean assertions out of where clauses when there is no
relationship, and (2) they will be allowed to order the statements as desired. Under the current system, all boolean
clauses must be conjoined and expressed as the first item of the list (except after availability clauses, as the one exception)

-- E

On May 24, 2016, at 11:01 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

With the implementation of your proposal, will there be anything that can be written in where clauses that cannot be written after a comma (in the context of guard statements specifically)? If not, does the where clause become entirely a stylistic flourish?
On Tue, May 24, 2016 at 11:57 Erica Sadun <erica@ericasadun.com> wrote:
There is no way I could figure out how to restrict Boolean assertions to mentioned variables therefore I left where clauses entirely untouched.
I'd recommend people adopt in-house standards where Boolean assertions in where clauses should be semantically tied to the condition
clause that introduces them.

I will add this as a note.

-- E

On May 24, 2016, at 9:29 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Does this proposal distinguish between "where clauses [...] restricted to a Boolean assertion tied to variables connected to the binding or pattern condition" and "unrelated Boolean assertions [that] should be allowed to stand on their own"?

Or are both types of boolean assertions now permitted either following a comma or following a where clause?


(Erica Sadun) #20

The where clause is not a stylistic flourish because it is still best used to constrain conditions that are semantically
related to conditions. Upon acceptance as now, there are no compiler checks that mandate any relationship.

The difference is that (1) coders will be allowed to move Boolean assertions out of where clauses when there is no
relationship, and (2) they will be allowed to order the statements as desired. Under the current system, all boolean
clauses must be conjoined and expressed as the first item of the list (except after availability clauses, as the one exception)

-- E

···

On May 24, 2016, at 11:01 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

With the implementation of your proposal, will there be anything that can be written in where clauses that cannot be written after a comma (in the context of guard statements specifically)? If not, does the where clause become entirely a stylistic flourish?
On Tue, May 24, 2016 at 11:57 Erica Sadun <erica@ericasadun.com <mailto:erica@ericasadun.com>> wrote:
There is no way I could figure out how to restrict Boolean assertions to mentioned variables therefore I left where clauses entirely untouched.
I'd recommend people adopt in-house standards where Boolean assertions in where clauses should be semantically tied to the condition
clause that introduces them.

I will add this as a note.

-- E

On May 24, 2016, at 9:29 AM, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:

Does this proposal distinguish between "where clauses [...] restricted to a Boolean assertion tied to variables connected to the binding or pattern condition" and "unrelated Boolean assertions [that] should be allowed to stand on their own"?

Or are both types of boolean assertions now permitted either following a comma or following a where clause?