You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This proposal aims to allow the use of trailing commas, currently restricted to array and dictionary literals, in comma-separated lists whenever there are terminators that enable unambiguous parsing.
14
+
This proposal aims to allow the use of trailing commas, currently restricted to array and dictionary literals, in symmetrically delimited comma-separated lists.
14
15
15
16
## Motivation
16
17
@@ -48,7 +49,7 @@ The language has also seen the introduction of [parameter packs](https://github.
48
49
49
50
## Proposed solution
50
51
51
-
This proposal adds support for trailing commas in comma-separated lists when there's a clear terminator, which are the following:
52
+
This proposal adds support for trailing commas in symmetrically delimited comma-separated lists, which are the following:
52
53
53
54
- Tuples and tuple patterns.
54
55
@@ -66,7 +67,7 @@ This proposal adds support for trailing commas in comma-separated lists when the
66
67
) = velocity
67
68
```
68
69
69
-
- Parameter and argument lists of initializers, functions, enumassociated values, expression macros, attributes, and availability specs.
70
+
- Parameter and argument lists of initializers, functions, enumassociated values, expression macrosand attributes.
70
71
71
72
```swift
72
73
func foo(
@@ -114,10 +115,6 @@ This proposal adds support for trailing commas in comma-separated lists when the
114
115
)
115
116
}
116
117
117
-
if#unavailable(
118
-
iOS15,
119
-
watchOS9,
120
-
) { }
121
118
```
122
119
123
120
- Subscripts, including key path subscripts.
@@ -139,164 +136,158 @@ This proposal adds support for trailing commas in comma-separated lists when the
139
136
])
140
137
```
141
138
139
+
- Closure capture lists.
140
+
141
+
```swift
142
+
{ [
143
+
capturedValue1,
144
+
capturedValue2,
145
+
] in
146
+
}
147
+
```
148
+
149
+
- Generic parameters.
150
+
151
+
```swift
152
+
structS<
153
+
T1,
154
+
T2,
155
+
T3,
156
+
> { }
157
+
```
158
+
159
+
-String interpolation.
160
+
161
+
```swift
162
+
let s ="\(1, 2,)"
163
+
```
164
+
165
+
## Detailed Design
166
+
167
+
Trailing commas will be supported in comma-separated lists when symmetric delimiters (including `(...)`, `[...]`, and `<...>`) enable unambiguous parsing.
168
+
169
+
Note that the requirement for symmetric delimiters means that the following cases will not support trailing comma:
170
+
142
171
- `if`, `guard` and `while` condition lists.
143
172
144
173
```swift
145
174
if
146
175
condition1,
147
-
condition2,
176
+
condition2,❌
148
177
{ }
149
178
150
179
while
151
180
condition1,
152
-
condition2,
181
+
condition2,❌
153
182
{ }
154
183
155
184
guard
156
185
condition1,
157
-
condition2,
186
+
condition2,❌
158
187
else { }
159
188
```
189
+
190
+
- Enum case label lists.
191
+
192
+
```swift
193
+
enumE {
194
+
case
195
+
a,
196
+
b,
197
+
c, ❌
198
+
}
199
+
```
160
200
161
201
- `switch` case labels.
162
202
163
203
```swift
164
204
switch number {
165
205
case
166
206
1,
167
-
2,
207
+
2,❌
168
208
:
169
209
...
170
210
default:
171
211
..
172
212
}
173
213
```
174
-
175
-
- Closure capture lists.
176
-
177
-
```swift
178
-
{ [
179
-
capturedValue1,
180
-
capturedValue2,
181
-
] in
182
-
}
183
-
```
184
-
214
+
185
215
- Inheritance clauses.
186
216
187
217
```swift
188
218
structS:
189
219
P1,
190
220
P2,
191
-
P3,
221
+
P3, ❌
192
222
{ }
193
223
```
194
224
195
-
- Generic parameters.
196
-
197
-
```swift
198
-
structS<
199
-
T1,
200
-
T2,
201
-
T3,
202
-
> { }
203
-
```
204
-
205
225
- Generic `where` clauses.
206
226
207
227
```swift
208
228
structS<
209
229
T1,
210
230
T2,
211
-
T3
231
+
T3,
212
232
> where
213
233
T1:P1,
214
-
T2:P2,
234
+
T2:P2, ❌
215
235
{ }
216
236
```
217
237
218
-
-String interpolation
219
-
220
-
```swift
221
-
let s ="\(1, 2,)"
222
-
```
223
-
224
-
## Detailed Design
225
-
226
-
Trailing commas will be supported in comma-separated lists whenever there is a terminator clear enough that the parser can determine the end of the list. The terminator can be the symbols like `)`, `]`, `>`, `{` and `:`, a keyword like `where` or a pattern code like the body of a `if`, `guard` and `while` statement.
227
-
228
-
Note that the requirement for a terminator means that the following cases will not support trailing comma:
229
-
230
-
Enum case label lists:
238
+
Trailing commas will be allowed in single-element lists but not in zero-element lists, since the trailing comma is actually attached to the last element.
239
+
Supporting a zero-element list would require supporting _leading_ commas, which isn't what this proposal is about.
231
240
232
241
```swift
233
-
enum E {
234
-
case
235
-
a,
236
-
b,
237
-
c, // ❌ Expected identifier after comma in enum 'case' declaration
238
-
}
239
-
```
240
-
241
-
Inheritance clauses for associated types in a protocol declaration:
242
-
243
-
```swift
244
-
protocol Foo {
245
-
associatedtype T:
246
-
P1,
247
-
P2, // ❌ Expected type
248
-
}
242
+
(1,) // OK
243
+
(,) ❌ expected value in tuple
249
244
```
250
245
251
-
Generic `where` clauses for initializers and functions in a protocol declaration:
252
246
253
-
```swift
254
-
protocol Foo {
255
-
funcf<T1, T2>(a: T1, b: T2) where
256
-
T1:P1,
257
-
T2:P2, // ❌ Expected type
258
-
}
259
-
```
247
+
## Source compatibility
260
248
261
-
Trailing commas will be allowed in single-element lists but not in zero-element lists, since the trailing comma isactually attached to the last element. Supporting a zero-element list would require supporting _leading_ commas, which isn't what this proposal is about.
249
+
This is a purely additive change with no source compatibility impact.
262
250
263
-
```swift
264
-
(1,) // OK
265
-
(,) // ❌ expected value in tuple
266
-
```
251
+
## Alternatives considered
267
252
253
+
### Allow trailing comma in all comma-separated lists
268
254
269
-
## Source compatibility
255
+
Comma-separated lists that are not symmetrically delimited could also benefit from trailing comma support; for example, condition lists, in which reordering is fairly common.
256
+
However, these lists currently rely on the comma after the penultimate element to determine that what comes next is the last element, and some of them present challenges if relying on opening/closing delimiters instead.
270
257
271
-
Although this change won't impact existing valid code it will change how some invalid code is parsed. Consider the following:
258
+
At first sight, `{` may seem a reasonable closing delimiter for `if` and `while` condition lists, but conditions can have a `{` themselves.
272
259
273
260
```swift
274
261
if
275
-
condition1,
276
-
condition2,
277
-
{ // ❌ Function produces expected type 'Bool'; did you mean to call it with '()'?
278
-
returntrue
279
-
}
280
-
281
-
{ print("something") }
262
+
condition1,
263
+
condition2,
264
+
{ true }(),
265
+
{ }
282
266
```
283
267
284
-
Currently the parser uses the last comma to determine that whatever follows is the last condition, so `{ returntrue }` is a condition and `{ print("something") }` is the `if` body.
268
+
This particular case can be handled but, given how complex conditions can be, it's hard to conclude that there's absolutely no corner case where ambiguity can arise in currently valid code.
285
269
286
-
With trailing comma support, the parser will terminate the condition list before the first block that is a valid `if` body, so `{ returntrue }` will be parsed asthe `if` body and `{ print("something") }` will be parsed as an unused closure expression.
270
+
Inheritance lists and generic `where` clauses can appear in protocol definitons where there's no clear delimiter, making it harder to disambiguate where the list ends.
287
271
288
272
```swift
289
-
if
290
-
condition1,
291
-
condition2,
292
-
{
293
-
returntrue
273
+
protocolFoo {
274
+
associatedtypeT:
275
+
P1,
276
+
P2, ❌ Expected type
277
+
...
294
278
}
279
+
```
295
280
296
-
{ print("something") } // ❌ Closure expression is unused
281
+
```swift
282
+
protocolFoo {
283
+
associatedtypeT:
284
+
P1,
285
+
P2, ❌ Expected type
286
+
...
287
+
}
297
288
```
298
289
299
-
## Alternatives considered
290
+
Although some comma-separated lists without symmetric delimiters may have a clear terminator in some cases, this proposal restricts trailing comma support to symmetrically delimited ones where it's clear that the presence of a trailing comma will not cause parsing ambiguity.
300
291
301
292
### Eliding commas
302
293
@@ -312,3 +303,11 @@ print(
312
303
This was even [proposed](https://forums.swift.org/t/se-0257-eliding-commas-from-multiline-expression-lists/22889/188) and returned for revision back in 2019.
313
304
314
305
The two approaches are not mutually exclusive. There remain unresolved questions about how the language can accommodate elided commas, and adopting this proposal does not prevent that approach from being considered in the future.
306
+
307
+
## Revision History
308
+
309
+
- Update to address acceptance decision of restricting trailing comma to lists with symmetric delimiters.
310
+
311
+
## Acknowledgments
312
+
313
+
Thanks to Alex Hoppen, Xiaodi Wu and others for their help on the proposal text and implementation.
0 commit comments