Thinking about a cleaner `if` syntax

With Swift 1.2 the `if` syntax became a lot more powerful but also inconsistent.


Simply said the `if` syntax looks like the following (ignoring Swift 2's new pattern matching):

if <preconditions>, <assignment conditions> where <postconditions> {

It's evaluated from left to right.


For example:

if a && b && ..., let c = d, e = f, ... where g && h && ... {


Here a more natural hypothetical example:

if ready && shouldRead, let file = file, reader = file.reader where reader.available && reader.hasData {



It's weird that first a comma and later the `where` keyword is used to separate conditions.

In both cases they don't mean anything else than "and".


I'd suggest a simpler and more consistent syntax like this:

if ready && shouldRead && let file = file, reader = file.reader && reader.available && reader.hasData {


As before it's evaluated from left to right and the intent is much clearer.

Assignment conditions could now appear anywhere within the whole condition as long as they've all been evaluated when the `if` clause succeeds (e.g. not mixing `let`/`var` and `||`).


So this should be possible:

if let a = a && b && let c = d {


while this shoult not be:

if let a = a && (b || let c = d) {



Additionaly we could simplify `let x = x` to just `let x`:

if let x, y {

instead of

if let x = x, y = y {



Applying all of the improvements we could simplify the following code:


if ready, let file = file, reader = file.reader where reader.hasData {
    if let line = reader.readLine() where line == "test" {

to this:

if ready && let file, reader = file.reader && reader.hasData && let line = reader.readLine() && line == "test" {



What do you think?

Replies

I don't think you're correct about the current syntax. According to the book, 'where' is associated with the preceding 'let', so it's not a simple postcondition.


The syntax of the 'if' statement is an expression, followed by a series of:


— 'let' clauses, each of which my have a 'where' condition, and each of which may do multiple bindings, and/or

—or 'case' clauses.


The rationale for this is that it was introduced as a way of flattening multiple nested 'if' statements to prevent excessive indentation.


The '&&' syntax as a clause connector was suggested a couple of months ago, and rejected by the compiler team as an overly arbitrary co-opting the boolean operator.


Note that this flattened 'if' syntax was introduced in Swift 1.2. It's been partially superceded by by 'guard let', which flattens flatter, at the expense of being less concise.

Yes, it was introduced to reduce nesting but that's not relevant for this discussion about a cleaner ìf` syntax.


I just made some tests in Playground and noticed that the `if` syntax supports multiple `let + where` conditions.

So it's more like this:

if precondition, assignments, postcondition, assignments, postcondition {

e.g.

if a, let b = b where b.c, let d = b.d where d.e, … {


I know the syntax described here is simplified a lot and that the `where` part is related to the assignment but nevertheless it's how we use `if`.


The example above actually reads

if <a is true> and <the assignment of b succeeds> and <b.c is true> and <the assignment of d succeeds> and <d.e is true> then

So using `&&` to chain all conditions seems just natural and makes sense.


`let x = x` in an `if` condition is not that different from a boolean condition which means that the non-nil assignment succeeds and with the only addition being that it introduces a new variable in the current scope.


This:

if a && let b = b && b.c && let d = b.d && d.e {

is much easier to read and understand than this:

if a, let b = b where b.c, let d = b.d where d.e {


Since this is not about nesting but about a different syntax which is easier to use and to understand using `guard` does not help.

The opposite is true. Since `guard` basically supports the same syntax as `if` it causes the same confusion and inconsistency.