- Proposal: TBD
- Author: Erica Sadun
- Status: TBD
- Review manager: TBD
This proposal simplifies guard case
and if case
grammar. It drops the case
keyword and replaces the assignment sign with the pattern matching (~=
) operator. The results are simpler, they reads better, and it transfers the responsibility of saying "this is pattern matching" from case
to ~=
.
Swift-evolution thread:
[Pitch] Reimagining guard case
/if case
Swift's guard case
and if case
statements stand out for their unintuitive approach. They look like assignment statements but they are not assignment statements. They present difficulties for new language adopters because they combine several concepts in a confusing form. They are arguably underutilized by language experts.
Both guard case
and `if case statements perform simultaneous pattern matching and conditional binding. Here are examples demonstrating their use in current Swift:
enum Result<T> { case success(T), error(Error) }
// valid Swift
guard case let .success(value) = result
else { ... }
// valid Swift
guard case .success(let value) = result
else { ... }
The status quo is iteratively built up in this fashion:
=
performs assignmentlet x =
performs bindingif let x =
performs conditional bindingif case .foo(let x) =
performs conditional binding and pattern matching
When using if case
/guard case
in the absense of conditional binding, it duplicates basic pattern matching but uses less obvious semantics. These two statements are functionally identical:
if range ~= myValue { ... } // simpler
if case range = myValue { ... } // confusing
The problems with guard case
and if case
include:
- The
=
operator looks like assignment and not like pattern matching (~=
). - The
case
layout is both too close to aswitch
'scase
but doesn't follow its syntax. Inswitch
, acase
is followed by a colon, not an equal sign. - Using the
case
syntax is unneccessarily wordy. It incorporatescase
,=
, and optionallylet
/var
assignments.
This proposal replaces the current syntax with a simpler grammar that prioritizes pattern matching but mirrors basic conditional binding. The new syntax drops the case
keyword and replaces =
with ~=
. The results look like this:
guard let .success(value) ~= result else { ... }
guard .success(let value) ~= result else { ... }
if let .success(value) ~= result { ... }
if .success(let value) ~= result { ... }
guard let x? ~= anOptional else { ... }
if let x? ~= anOptional { ... }
In this update:
- The
case
keyword is subsumed into the (existing) pattern matching operator - The statements adopt the existing
if-let
andguard-let
syntax, includingOptional
syntactic sugar.
if let x = anOptional { ... } // current
if case let x? = anOptional { ... } // current, would be removed
if let x? ~= anOptional { ... } // proposed replacement for `if case`
On adopting this syntax, the two identical range tests naturally unify to this single version:
if range ~= myValue { ... } // before
if case range = myValue { ... } // before
if range ~= myValue { ... } // after
Using pattern matching without conditional binding naturally simplifies to a standalone Boolean condition clause.
This proposal does not address switch case
or for case
.
This proposal is breaking and would require migration.
- Leaving the grammar as-is, albeit confusing
- Retaining
case
and replacing the equal sign with~=
(pattern matching) or:
(to match the switch statement).
@erica, did some minor improvements on this gist. Feel free to take a look at my fork.