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
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to