Hi swift-evolution,
I've been working on a pitch I think you're all going to love, as well as the corresponding implementation
Control Flow Negation Statements
- Proposal: SE-NNNN
- Author: Harlan Haskins
- Review Manager: TBD
- Status: Awaiting review
- Implementation: apple/swift#23704
Introduction
This proposal adds negated forms of the various control-flow operations in the Swift language. Specifically, it introduces negated forms of if
, guard
, while
, do
, and defer
.
Motivation
Swift is a uniquely expressive language, but there are still places where boilerplate is necessary. One egregious example of missing syntactic sugar revolves around condition negation. Frequently, developers want to conditionalize their code on a condition they intend to be false. Swift has a prefix operator, !
, that allows for negating a boolean, but this can be difficult to see when in front of a large expression, and sometimes requires parentheses around nested logical expressions.
Instead, letâs provide negated forms of common control flow. While weâre at it, we can also add negated forms of do
and defer
, to complete the picture.
Proposed solution
I propose adding 5 new statements to Swift: ifnât
, guardnât
, whilenât
, donât
, and defernât
. These will be analogues to the if
, guard
, while
, do
, and defer
statement, but with the opposite semantics.
Detailed design
ifnât
ifnt-statement â `ifnât` condition-list code-block else-clause?
else-clause â `else` code-block | `else` if-statement | `else` ifnât-statement
An ifnât
statement executes the provided code block if the provided condition evaluates to false. There is no support for ifnât let
or ifnât case
statements.
guardnât
guardnt-statement â `guardnât` condition-list `else` code-block
A guardnât
statement executes the provided code block if the provided condition evaluates to true
. There is no support for guardnât let
or ifnât case
statements. All the traditional rules of guard
still apply.
whilenât
whilent-statement â `whilenât` condition-list code-block
A whilenât
statement executes the provided code block repeatedly until the provided condition evaluates to true
. There is no support for whilenât let
or whilenât case
statements.
donât
dont-statement â `donât` code-block
A donât
statement does not execute the code in the provided code block.
defernât
defernt-statement â `defernât` code-block
A defernât
statement does not schedule the code in the provided code block to be run at the end of the current execution scope. These blocks, because they are not scheduled at all, do not execute in reverse order.
Source compatibility
These changes are purely additive, no source changes will be necessary to adopt them.
Effect on ABI stability
These statements do not meaningfully affect ABI surface.
Effect on API resilience
These statements do not affect the API of the declarations in which they are used.
Alternatives considered
There are many more statements whose semantics can be negated. They are left to future proposals, as I did not want to balloon this proposal.
ifnât let
, guardnât let
, whilenât let
We could support parameter binding in negated statements. One possible implementation strategy is to only execute the block if the value could not be bound, and do not introduce the binding into the new scope.
ifnât case
, guardnât case
, whilenât case
Similar to the above, we could support pattern matching. A possible strategy could be to match all patterns except the written one, and explicitly not bind any pattern bindings.
catchnât
We could extend the existing catch
clause to support catchnât
, which will only execute if the caught error does not match the provided pattern.
fornât
It is unclear how this would work. Maybe this would execute if the sequence returned nil
immediately, without any intermediate results.
returnât
This could be a no-op, or this could only work for boolean return values and negate their value.