Skip to content

Commit f70d6c4

Browse files
jtbandeserica
authored andcommitted
[Status] Add section for “Implementation in progress” (swiftlang#558)
1 parent 4112109 commit f70d6c4

File tree

3 files changed

+144
-6
lines changed

3 files changed

+144
-6
lines changed

index.xml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<proposal id="0039" status="implemented" swift-version="3" name="Modernizing Playground Literals" filename="0039-playgroundliterals.md"/>
4343
<proposal id="0040" status="implemented" swift-version="3" name="Replacing Equal Signs with Colons For Attribute Arguments" filename="0040-attributecolons.md"/>
4444
<proposal id="0041" status="rejected" name="Updating Protocol Naming Conventions for Conversions" filename="0041-conversion-protocol-conventions.md"/>
45-
<proposal id="0042" status="accepted" name="Flattening the function type of unapplied method references" filename="0042-flatten-method-types.md"/>
45+
<proposal id="0042" status="implementing" name="Flattening the function type of unapplied method references" filename="0042-flatten-method-types.md"/>
4646
<proposal id="0043" status="implemented" swift-version="3" name="Declare variables in 'case' labels with multiple patterns" filename="0043-declare-variables-in-case-labels-with-multiple-patterns.md"/>
4747
<proposal id="0044" status="implemented" swift-version="3" name="Import as Member" filename="0044-import-as-member.md"/>
4848
<proposal id="0045" status="implemented" swift-version="3.1" name="Add prefix(while:) and drop(while:) to the stdlib" filename="0045-scan-takewhile-dropwhile.md"/>
@@ -75,12 +75,12 @@
7575
<proposal id="0072" status="implemented" swift-version="3" name="Fully eliminate implicit bridging conversions from Swift" filename="0072-eliminate-implicit-bridging-conversions.md"/>
7676
<proposal id="0073" status="rejected" name="Marking closures as executing exactly once" filename="0073-noescape-once.md"/>
7777
<proposal id="0074" status="rejected" name="Implementation of Binary Search functions" filename="0074-binary-search.md"/>
78-
<proposal id="0075" status="accepted" name="Adding a Build Configuration Import Test" filename="0075-import-test.md"/>
78+
<proposal id="0075" status="implementing" name="Adding a Build Configuration Import Test" filename="0075-import-test.md"/>
7979
<proposal id="0076" status="implemented" swift-version="3" name="Add overrides taking an UnsafePointer source to non-destructive copying methods on UnsafeMutablePointer" filename="0076-copying-to-unsafe-mutable-pointer-with-unsafe-pointer-source.md"/>
8080
<proposal id="0077" status="implemented" swift-version="3" name="Improved operator declarations" filename="0077-operator-precedence.md"/>
8181
<proposal id="0078" status="deferred" name="Implement a rotate algorithm, equivalent to std::rotate() in C++" filename="0078-rotate-algorithm.md"/>
8282
<proposal id="0079" status="deferred" name="Allow using optional binding to upgrade `self` from a weak to strong reference" filename="0079-upgrade-self-from-weak-to-strong.md"/>
83-
<proposal id="0080" status="accepted" name="Failable Numeric Conversion Initializers" filename="0080-failable-numeric-initializers.md"/>
83+
<proposal id="0080" status="implementing" name="Failable Numeric Conversion Initializers" filename="0080-failable-numeric-initializers.md"/>
8484
<proposal id="0081" status="implemented" swift-version="3" name="Move `where` clause to end of declaration" filename="0081-move-where-expression.md"/>
8585
<proposal id="0082" status="accepted" name="Package Manager Editable Packages" filename="0082-swiftpm-package-edit.md"/>
8686
<proposal id="0083" status="deferred" name="Remove bridging conversion behavior from dynamic casts" filename="0083-remove-bridging-from-dynamic-casts.md"/>
@@ -104,7 +104,7 @@
104104
<proposal id="0101" status="implemented" swift-version="3" name="Reconfiguring `sizeof` and related functions into a unified `MemoryLayout` struct" filename="0101-standardizing-sizeof-naming.md"/>
105105
<proposal id="0102" status="implemented" swift-version="3" name="Remove `@noreturn` attribute and introduce an empty `Never` type" filename="0102-noreturn-bottom-type.md"/>
106106
<proposal id="0103" status="implemented" swift-version="3" name="Make non-escaping closures the default" filename="0103-make-noescape-default.md"/>
107-
<proposal id="0104" status="accepted" name="Protocol-oriented integers" filename="0104-improved-integers.md"/>
107+
<proposal id="0104" status="implementing" name="Protocol-oriented integers" filename="0104-improved-integers.md"/>
108108
<proposal id="0105" status="rejected" name="Removing Where Clauses from For-In Loops" filename="0105-remove-where-from-forin-loops.md"/>
109109
<proposal id="0106" status="implemented" swift-version="3" name="Add a `macOS` Alias for the `OSX` Platform Configuration Test" filename="0106-rename-osx-to-macos.md"/>
110110
<proposal id="0107" status="implemented" swift-version="3" name="UnsafeRawPointer API" filename="0107-unsaferawpointer.md"/>
@@ -141,15 +141,15 @@
141141
<proposal id="0138" status="implemented" swift-version="3.0.1" name="UnsafeRawBufferPointer" filename="0138-unsaferawbufferpointer.md"/>
142142
<proposal id="0139" status="implemented" swift-version="3.0.1" name="Bridge Numeric Types to `NSNumber` and Cocoa Structs to `NSValue`" filename="0139-bridge-nsnumber-and-nsvalue.md"/>
143143
<proposal id="0140" status="implemented" swift-version="3.0.1" name="Bridge `Optional` As Its Payload Or `NSNull`" filename="0140-bridge-optional-to-nsnull.md"/>
144-
<proposal id="0141" status="accepted" swift-version="4" name="Availability by Swift version" filename="0141-available-by-swift-version.md"/>
144+
<proposal id="0141" status="implemented" swift-version="3.1" name="Availability by Swift version" filename="0141-available-by-swift-version.md"/>
145145
<proposal id="0142" status="accepted" swift-version="4" name="Permit where clauses to constrain associated types" filename="0142-associated-types-constraints.md"/>
146146
<proposal id="0143" status="active" swift-version="4" name="Conditional conformances" filename="0143-conditional-conformances.md"/>
147147
<proposal id="0144" status="rejected" swift-version="4" name="Allow Single Dollar Sign as a Valid Identifier" filename="0144-allow-single-dollar-sign-as-valid-identifier.md"/>
148148
<proposal id="0145" status="returned" swift-version="4" name="Package Manager Version Pinning" filename="0145-package-manager-version-pinning.md"/>
149149

150150
<!--
151151
Recognized values for a proposal's status:
152-
implemented, accepted, active, scheduled, awaiting, deferred, returned, rejected, withdrawn
152+
implemented, implementing, accepted, active, scheduled, awaiting, deferred, returned, rejected, withdrawn
153153
154154
Note: status="implemented" also requires swift-version="XX".
155155
-->

index.xslt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
<xsl:with-param name="proposals" select="proposal[@status='accepted']"/>
3939
</xsl:call-template>
4040

41+
<xsl:call-template name="section">
42+
<xsl:with-param name="title">Implementation in progress</xsl:with-param>
43+
<xsl:with-param name="proposals" select="proposal[@status='implementing']"/>
44+
</xsl:call-template>
45+
4146
<xsl:call-template name="section">
4247
<xsl:with-param name="title">Implemented (Swift 4)</xsl:with-param>
4348
<xsl:with-param name="proposals" select="proposal[@status='implemented'][@swift-version='4']"/>
@@ -246,6 +251,10 @@
246251
a.number.status-implemented {
247252
background-color: #319021;
248253
}
254+
a.number.status-implementing {
255+
background-color: #5abc4e;
256+
background: repeating-linear-gradient(135deg, #5abc4e, #5abc4e 14.29%, #319021 14.29%, #319021 28.57%);
257+
}
249258
a.number.status-accepted {
250259
background-color: #5abc4e;
251260
}

proposals/9999-ifcaseguardcase.md

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Simplifying `guard case`/`if case` syntax
2+
3+
* Proposal: TBD
4+
* Author: [Erica Sadun](https://github.com/erica)
5+
* Status: TBD
6+
* Review manager: TBD
7+
8+
## Introduction
9+
10+
This proposal re-architects `guard case` and `if case` grammar for unwrapping complex enumerations. It drops the `case` keyword from `if` and `guard`, replaces `=` with `~=`, and introduces the `:=` operator that combines declaration with assignment.
11+
12+
Swift-evolution thread:
13+
[\[Pitch\] Reimagining `guard case`/`if case`](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20161024/tbd.html)
14+
15+
## Motivation
16+
17+
Swift's `guard case` and `if case` design aligns statement layout with the `switch` statement:
18+
19+
```swift
20+
switch value {
21+
case let .enumeration(embedded): ...
22+
}
23+
24+
if case let .enumeration(embedded) = value
25+
```
26+
27+
This grammar unifies the two approaches and offers an overall conceptual "win". However, real-world users do not think about this parallel construction or naturally connect the two layouts.
28+
29+
* `guard case` and `if case` look like assignment statements but they are *not* assignment statements. This violates the [principle of least astonishment](https://en.wikipedia.org/wiki/Principle_of_least_astonishment).
30+
* In `switch`, a `case` is followed by a colon, not an assignment operator.
31+
* Swift has a pattern matching operator (`~=`) that isn't used here.
32+
* `case` syntax is wordy, including `case`, `=`, and optionally `let`/`var` assignment.
33+
34+
`guard case` and `if case` perform simultaneous pattern matching and conditional binding. These examples demonstrate their use for a simple one-associated-value enumeration:
35+
36+
```swift
37+
enum Result<T> { case success(T), error(Error) }
38+
39+
// valid Swift
40+
guard case let .success(value) = result
41+
else { ... }
42+
guard case .success(let value) = result
43+
else { ... }
44+
45+
// valid Swift
46+
if case .success(let value) = result { ... }
47+
if case let .success(value) = result { ... }
48+
```
49+
50+
The status quo for the `=` operator is iteratively built up in this fashion:
51+
52+
* `=` performs assignment
53+
* `let x =` performs binding
54+
* `if let x =` performs conditional binding on optionals
55+
* `if case .foo(let x) = ` and `if case let .foo(x) =` performs conditional binding on enumerations *and* applies pattern matching
56+
57+
Using `if case`/`guard case` in the absense of conditional binding duplicates basic pattern matching with less obvious meaning. These two statements are functionally identical:
58+
59+
```swift
60+
if range ~= myValue { ... } // simpler
61+
if case range = myValue { ... } // confusing
62+
```
63+
64+
## Detailed Design
65+
66+
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:
67+
68+
```swift
69+
guard let .success(value) ~= result else { ... }
70+
guard .success(let value) ~= result else { ... }
71+
if let .success(value) ~= result { ... }
72+
if .success(let value) ~= result { ... }
73+
guard let x? ~= anOptional else { ... }
74+
if let x? ~= anOptional { ... }
75+
```
76+
77+
The design includes Swift's current `let`-placement flexibility and `let`-`var` mix-and-match placement. Users may choose to use `var` instead of `let` to bind to a variable instead of a constant. In this design:
78+
79+
* The `case` keyword is subsumed into the (existing) pattern matching operator
80+
* The statements adopt the existing `if-let`/`if var` and `guard-let`/`guard var` syntax, including `Optional` syntactic sugar.
81+
82+
```swift
83+
if let x = anOptional { ... } // current
84+
if case let x? = anOptional { ... } // current, would be removed
85+
86+
if let x? ~= anOptional { ... } // proposed replacement for `if case`
87+
```
88+
89+
Introducing a further new `:=` "declare and assign" operator eliminates the need for explicit `let`:
90+
91+
```swift
92+
guard .success(value) := result else { ... } // clean and elegant
93+
if .success(value) := result { ... } // clean and elegant
94+
guard x? := anOptional else { ... } // newly legal, although unnecessary
95+
```
96+
97+
Assignments to variables require the `var` keyword, and `let` will be permitted even if it is not required, enabling coders to clarify the distinct roles in mix-and-match pattern matching:
98+
99+
```swift
100+
guard .pair(value1, var value2) := result else { ... } // implied let
101+
guard .pair(let value1, var value2) := result else { ... } // explicit let
102+
if .success(var value) := result { ... } // variable assignment
103+
guard var x? := anOptional else { ... } // variable assignment
104+
guard var x := anOptional else { ... } // simpler variable assignment
105+
guard var x = anOptional else { ... } // even simpler (current) variable assignment
106+
guard x := anOptional else { ... } // new constant assignment
107+
```
108+
109+
Pattern matching without conditional binding simplifies to a standalone Boolean condition clause. On adopting this syntax, the two identical range tests naturally unify to this single version:
110+
111+
```swift
112+
if range ~= myValue { ... } // before
113+
if case range = myValue { ... } // before
114+
115+
if range ~= myValue { ... } // after
116+
```
117+
118+
### Excluded from this proposal
119+
120+
This proposal does not address `switch case` or `for case`.
121+
122+
## Impact on Existing Code
123+
124+
This proposal is breaking and would require migration.
125+
126+
## Alternatives Considered
127+
128+
* Leaving the grammar as-is, albeit confusing
129+
* Retaining `case` and replacing the equal sign with `~=` (pattern matching) or `:` (to match the switch statement).

0 commit comments

Comments
 (0)