Shorthand syntax for optional binding conditions that shadow an existing variable (e.g. if let foo = foo
) has come up many times over the years. Most recently, it was discussed in Let's fix if let
syntax. I felt like the reception in that thread was reasonably positive, so I implemented support for this in apple/swift#40694. Here's a pitch (full proposal document here):
Introduction
Optional binding using if let foo = foo { ... }
, to create an unwrapped variable that shadows an existing optional variable, is an extremely common pattern. This pattern requires the author to repeat the referenced identifier twice, which can cause these optional binding conditions to be verbose, especialy when using lengthy variable names. We should introduce a shorthand syntax for optional binding when shadowing an existing variable:
let foo: Foo? = ...
if let foo {
// `foo` is of type `Foo`
}
Motivation
Reducing duplication, especially of lengthy variable names, makes code both easier to write and easier to read.
For example, this statement that unwraps someLengthyVariableName
and anotherImportantVariable
is rather arduous to read (and was without a doubt arduous to write):
let someLengthyVariableName: Foo? = ...
let anotherImportantVariable: Bar? = ...
if let someLengthyVariableName = someLengthyVariableName, let anotherImportantVariable = anotherImportantVariable {
...
}
Proposed solution
If we instead omit the right-hand expression, and allow the compiler to automatically shadow the existing variable with that name, these optional bindings are much less verbose, and noticably easier to read / write:
let someLengthyVariableName: Foo? = ...
let anotherImportantVariable: Bar? = ...
if let someLengthyVariableName, let anotherImportantVariable {
...
}
This is a fairly natural extension to the existing syntax for optional binding conditions. Using let
(or var
) here makes it abundantly clear that a new variable is being defined, which is especially important when used with mutable value types. Using let
/ var
here also allows us to avoid adding any new keywords to the language.
Detailed design
Specifically, this proposal extends the Swift grammar for optional-binding-condition
s.
This is currently defined as:
optional-binding-condition → let pattern initializer | var pattern initializer
and would be updated to:
optional-binding-condition → let pattern initializeropt | var pattern initializeropt
This would apply to all conditional control flow statements:
if let foo { ... }
if var foo { ... }
else if let foo { ... }
else if var foo { ... }
guard let foo else { ... }
guard var foo else { ... }
while let foo { ... }
while var foo { ... }
The compiler would synthesize an initializer expression that references the variable being shadowed.
For example:
if let foo { ... }
is transformed into:
if let foo = foo { ... }