Skip to content

Commit 523461b

Browse files
authored
Merge pull request #2460 from stzn/patch-3
[SE-0430] Change `sendable` to `sending`
2 parents 129bc97 + 4dded8e commit 523461b

File tree

1 file changed

+73
-73
lines changed

1 file changed

+73
-73
lines changed

proposals/0430-transferring-parameters-and-results.md

Lines changed: 73 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# `sendable` parameter and result values
1+
# `sending` parameter and result values
22

33
* Proposal: [SE-0430](0430-transferring-parameters-and-results.md)
44
* Authors: [Michael Gottesman](https://github.com/gottesmm), [Holly Borla](https://github.com/hborla), [John McCall](https://github.com/rjmccall)
@@ -12,8 +12,8 @@
1212
## Introduction
1313

1414
This proposal extends region isolation to enable the application of an explicit
15-
`sendable` annotation to function parameters and results. A function parameter
16-
or result that is annotated with `sendable` is required to be disconnected at
15+
`sending` annotation to function parameters and results. A function parameter
16+
or result that is annotated with `sending` is required to be disconnected at
1717
the function boundary and thus possesses the capability of being safely sent
1818
across an isolation domain or merged into an actor-isolated region in the
1919
function's body or the function's caller respectively.
@@ -140,17 +140,17 @@ used again after the call to `resume(returning:)`.
140140

141141
This proposal enables explicitly specifying parameter and result values as
142142
possessing the capability of being sent over an isolation boundary by annotating
143-
the value with a contextual `sendable` keyword:
143+
the value with a contextual `sending` keyword:
144144

145145
```swift
146146
public struct CheckedContinuation<T, E: Error>: Sendable {
147-
public func resume(returning value: sendable T)
147+
public func resume(returning value: sending T)
148148
}
149149

150150
public func withCheckedContinuation<T>(
151151
function: String = #function,
152152
_ body: (CheckedContinuation<T, Never>) -> Void
153-
) async -> sendable T
153+
) async -> sending T
154154
```
155155

156156
## Detailed design
@@ -166,35 +166,35 @@ the value's entire region implying that all uses of the value (and anything
166166
non-`Sendable` typed that can be reached from the value) must end in the source
167167
concurrency context before any uses can begin in the destination concurrency
168168
context. Swift achieves this property by requiring that the value is in a
169-
disconnected region and we say that such a value is a `sendable` value.
169+
disconnected region and we say that such a value is a `sending` value.
170170

171171
Thus a newly-created value with no connections to existing regions is always a
172-
`sendable` value:
172+
`sending` value:
173173

174174
```swift
175175
func f() async {
176-
// This is a `sendable` value since we can transfer it safely...
176+
// This is a `sending` value since we can transfer it safely...
177177
let ns = NonSendable()
178178

179179
// ... here by calling 'sendToMain'.
180180
await sendToMain(ns)
181181
}
182182
```
183183

184-
Once defined, a `sendable` value can be merged into other isolation
184+
Once defined, a `sending` value can be merged into other isolation
185185
regions. Once merged, such regions, if not disconnected, will prevent the value
186186
from being sent to another isolation domain implying that the value is no longer
187-
a `sendable` value:
187+
a `sending` value:
188188

189189
```swift
190190
actor MyActor {
191191
var myNS: NonSendable
192192

193193
func g() async {
194-
// 'ns' is initially a `sendable` value since it is in a disconnected region...
194+
// 'ns' is initially a `sending` value since it is in a disconnected region...
195195
let ns = NonSendable()
196196

197-
// ... but once we assign 'ns' into 'myNS', 'ns' is no longer a sendable
197+
// ... but once we assign 'ns' into 'myNS', 'ns' is no longer a sending
198198
// value...
199199
myNS = ns
200200

@@ -204,43 +204,43 @@ actor MyActor {
204204
}
205205
```
206206

207-
If a `sendable` value's isolation region is merged into another disconnected
208-
isolation region, then the value is still considered to be `sendable` since two
207+
If a `sending` value's isolation region is merged into another disconnected
208+
isolation region, then the value is still considered to be `sending` since two
209209
disconnected regions when merged form a new disconnected region:
210210

211211
```swift
212212
func h() async {
213-
// This is a `sendable` value.
214-
let ns = NonSendable()
213+
// This is a `sending` value.
214+
let ns = Nonsending()
215215

216-
// This also a `sendable value.
216+
// This also a `sending value.
217217
let ns2 = NonSendable()
218218

219219
// Since both ns and ns2 are disconnected, the region associated with
220-
// tuple is also disconnected and thus 't' is a `sendable` value...
220+
// tuple is also disconnected and thus 't' is a `sending` value...
221221
let t = (ns, ns2)
222222

223223
// ... that can be sent across a concurrency boundary safely.
224224
await sendToMain(ns)
225225
}
226226
```
227227

228-
### Sendable Parameters and Results
228+
### sending Parameters and Results
229229

230-
A `sendable` function parameter requires that the argument value be in a
230+
A `sending` function parameter requires that the argument value be in a
231231
disconnected region. At the point of the call, the disconnected region is no
232232
longer in the caller's isolation domain, allowing the callee to send the
233233
parameter value to a region that is opaque to the caller:
234234

235235
```swift
236236
@MainActor
237-
func acceptSend(_: sendable NonSendable) {}
237+
func acceptSend(_: sending NonSendable) {}
238238

239239
func sendToMain() async {
240240
let ns = NonSendable()
241241

242242
// error: sending 'ns' may cause a race
243-
// note: 'ns' is passed as a 'sendable' parameter to 'acceptSend'. Local uses could race with
243+
// note: 'ns' is passed as a 'sending' parameter to 'acceptSend'. Local uses could race with
244244
// later uses in 'acceptSend'.
245245
await acceptSend(ns)
246246

@@ -253,28 +253,28 @@ What the callee does with the argument value is opaque to the caller; the callee
253253
may send the value away, or it may merge the value to the isolation region of
254254
one of the other parameters.
255255

256-
A `sendable` result requires that the function implementation returns a value in
256+
A `sending` result requires that the function implementation returns a value in
257257
a disconnected region:
258258

259259
```swift
260260
@MainActor
261261
struct S {
262262
let ns: NonSendable
263263

264-
func getNonSendableInvalid() -> sendable NonSendable {
264+
func getNonSendableInvalid() -> sending NonSendable {
265265
// error: sending 'self.ns' may cause a data race
266-
// note: main actor-isolated 'self.ns' is returned as a 'sendable' result.
266+
// note: main actor-isolated 'self.ns' is returned as a 'sending' result.
267267
// Caller uses could race against main actor-isolated uses.
268268
return ns
269269
}
270270

271-
func getNonSendable() -> sendable NonSendable {
271+
func getNonSendable() -> sending NonSendable {
272272
return NonSendable() // okay
273273
}
274274
}
275275
```
276276

277-
The caller of a function returning a `sendable` result can assume the value is
277+
The caller of a function returning a `sending` result can assume the value is
278278
in a disconnected region, enabling non-`Sendable` typed result values to cross
279279
an actor isolation boundary:
280280

@@ -290,75 +290,75 @@ nonisolated func f(s: S) async {
290290

291291
### Function subtyping
292292

293-
For a given type `T`, `sendable T` is a subtype of `T`. `sendable` is
293+
For a given type `T`, `sending T` is a subtype of `T`. `sending` is
294294
contravariant in parameter position; if a function type is expecting a regular
295-
parameter of type `T`, it's perfectly valid to pass a `sendable T` value
295+
parameter of type `T`, it's perfectly valid to pass a `sending T` value
296296
that is known to be in a disconnected region. If a function is expecting a
297-
parameter of type `sendable T`, it is not valid to pass a value that is not
297+
parameter of type `sending T`, it is not valid to pass a value that is not
298298
in a disconnected region:
299299

300300
```swift
301-
func sendableParameterConversions(
302-
f1: (sendable NonSendable) -> Void,
301+
func sendingParameterConversions(
302+
f1: (sending NonSendable) -> Void,
303303
f2: (NonSendable) -> Void
304304
) {
305-
let _: (sendable NonSendable) -> Void = f1 // okay
306-
let _: (sendable NonSendable) -> Void = f2 // okay
305+
let _: (sending NonSendable) -> Void = f1 // okay
306+
let _: (sending NonSendable) -> Void = f2 // okay
307307
let _: (NonSendable) -> Void = f1 // error
308308
}
309309
```
310310

311-
`sendable` is covariant in result position. If a function returns a value
312-
of type `sendable T`, it's valid to instead treat the result as if it were
311+
`sending` is covariant in result position. If a function returns a value
312+
of type `sending T`, it's valid to instead treat the result as if it were
313313
merged with the other parameters. If a function returns a regular value of type
314314
`T`, it is not valid to assume the value is in a disconnected region:
315315

316316
```swift
317-
func sendableResultConversions(
318-
f1: () -> sendable NonSendable,
317+
func sendingResultConversions(
318+
f1: () -> sending NonSendable,
319319
f2: () -> NonSendable
320320
) {
321-
let _: () -> sendable NonSendable = f1 // okay
322-
let _: () -> sendable NonSendable = f2 // error
321+
let _: () -> sending NonSendable = f1 // okay
322+
let _: () -> sending NonSendable = f2 // error
323323
let _: () -> NonSendable = f1 // okay
324324
}
325325
```
326326

327327
### Protocol conformances
328328

329-
A protocol requirement may include `sendable` parameter or result annotations:
329+
A protocol requirement may include `sending` parameter or result annotations:
330330

331331
```swift
332332
protocol P1 {
333-
func requirement(_: sendable NonSendable)
333+
func requirement(_: sending NonSendable)
334334
}
335335

336336
protocol P2 {
337-
func requirement() -> sendable NonSendable
337+
func requirement() -> sending NonSendable
338338
}
339339
```
340340

341341
Following the function subtyping rules in the previous section, a protocol
342-
requirement with a `sendable` parameter may be witnessed by a function with a
342+
requirement with a `sending` parameter may be witnessed by a function with a
343343
non-`Sendable` typed parameter:
344344

345345
```swift
346346
struct X1: P1 {
347-
func requirement(_: sendable NonSendable) {}
347+
func requirement(_: sending NonSendable) {}
348348
}
349349

350350
struct X2: P1 {
351351
func requirement(_: NonSendable) {}
352352
}
353353
```
354354

355-
A protocol requirement with a `sendable` result must be witnessed by a function
356-
with a `sendable` result, and a requirement with a plain result of type `T` may
357-
be witnessed by a function returning a `sendable T`:
355+
A protocol requirement with a `sending` result must be witnessed by a function
356+
with a `sending` result, and a requirement with a plain result of type `T` may
357+
be witnessed by a function returning a `sending T`:
358358

359359
```swift
360360
struct Y1: P1 {
361-
func requirement() -> sendable NonSendable {
361+
func requirement() -> sending NonSendable {
362362
return NonSendable()
363363
}
364364
}
@@ -371,42 +371,42 @@ struct Y2: P1 {
371371
}
372372
```
373373

374-
### `sendable inout` parameters
374+
### `sending inout` parameters
375375

376-
A `sendable` parameter can also be marked as `inout`, meaning that the argument
376+
A `sending` parameter can also be marked as `inout`, meaning that the argument
377377
value must be in a disconnected region when passed to the function, and the
378378
parameter value must be in a disconnected region when the function
379-
returns. Inside the function, the `sendable inout` parameter can be merged with
379+
returns. Inside the function, the `sending inout` parameter can be merged with
380380
actor-isolated callees or further sent as long as the parameter is
381381
re-assigned a value in a disconnected region upon function exit.
382382

383-
### Ownership convention for `sendable` parameters
383+
### Ownership convention for `sending` parameters
384384

385-
When a call passes an argument to a `sendable` parameter, the caller cannot
386-
use the argument value again after the callee returns. By default `sendable`
385+
When a call passes an argument to a `sending` parameter, the caller cannot
386+
use the argument value again after the callee returns. By default `sending`
387387
on a function parameter implies that the callee consumes the parameter. Like
388-
`consuming` parameters, a `sendable` parameter can be re-assigned inside
389-
the callee. Unlike `consuming` parameters, `sendable` parameters do not
388+
`consuming` parameters, a `sending` parameter can be re-assigned inside
389+
the callee. Unlike `consuming` parameters, `sending` parameters do not
390390
have no-implicit-copying semantics.
391391

392392
To opt into no-implicit-copying semantics or to change the default ownership
393-
convention, `sendable` may also be paired with an explicit `consuming` or
393+
convention, `sending` may also be paired with an explicit `consuming` or
394394
`borrowing` ownership modifier:
395395

396396
```swift
397-
func sendableConsuming(_ x: consuming sendable T) { ... }
398-
func sendableBorrowing(_ x: borrowing sendable T) { ... }
397+
func sendingConsuming(_ x: consuming sending T) { ... }
398+
func sendingBorrowing(_ x: borrowing sending T) { ... }
399399
```
400400

401401
Note that an explicit `borrowing` annotation always implies no-implicit-copying,
402402
so there is no way to change the default ownership convention of a
403-
`sendable` parameter without also opting into no-implicit-copying semantics.
403+
`sending` parameter without also opting into no-implicit-copying semantics.
404404

405405
### Adoption in the Concurrency library
406406

407407
There are several APIs in the concurrency library that send a parameter across
408408
isolation boundaries and don't need the full guarnatees of `Sendable`. These
409-
APIs will instead adopt `sendable` parameters:
409+
APIs will instead adopt `sending` parameters:
410410

411411
* `CheckedContinuation.resume(returning:)`
412412
* `Async{Throwing}Stream.Continuation.yield(_:)`
@@ -418,11 +418,11 @@ because `UnsafeContinuation` deliberately opts out of correctness checking.
418418

419419
## Source compatibility
420420

421-
In the Swift 5 language mode, `sendable` diagnostics are suppressed under
421+
In the Swift 5 language mode, `sending` diagnostics are suppressed under
422422
minimal concurrency checking, and diagnosed as warnings under strict concurrency
423423
checking. The diagnostics are errors in the Swift 6 language mode, as shown in
424424
the code examples in this proposal. This diagnostic behavior based on language
425-
mode allows `sendable` to be adopted in existing Concurrency APIs including
425+
mode allows `sending` to be adopted in existing Concurrency APIs including
426426
`CheckedContinuation`.
427427

428428
## ABI compatibility
@@ -431,21 +431,21 @@ This proposal does not change how any existing code is compiled.
431431

432432
## Implications on adoption
433433

434-
Adding `sendable` to a parameter is more restrictive at the caller, and
435-
more expressive in the callee. Adding `sendable` to a result type is more
434+
Adding `sending` to a parameter is more restrictive at the caller, and
435+
more expressive in the callee. Adding `sending` to a result type is more
436436
restrictive in the callee, and more expressive in the caller.
437437

438-
For libraries with library evolution, `sendable` changes name mangling, so
438+
For libraries with library evolution, `sending` changes name mangling, so
439439
any adoption must preserve the mangling using `@_silgen_name`. Adoping
440-
`sendable` must preserve the ownership convention of parameters; no
440+
`sending` must preserve the ownership convention of parameters; no
441441
additional annotation is necessary if the parameter is already (implicitly or
442442
explicitly) `consuming`.
443443

444444
## Future directions
445445

446446
### `Disconnected` types
447447

448-
`sendable` requires parameter and result values to be in a disconnected
448+
`sending` requires parameter and result values to be in a disconnected
449449
region at the function boundary, but there is no way to preserve that a value
450450
is in a disconnected region through stored properties, collections, function
451451
calls, etc. To preserve that a value is in a disconnected region through the
@@ -455,11 +455,11 @@ would conform to `Sendable`, constructing a `Disconnected` instance would
455455
require the value it wraps to be in a disconnected region, and a value of type
456456
`Disconnected` can never be merged into another isolation region.
457457

458-
This would enable important patterns that take a `sendable T` parameter, store
458+
This would enable important patterns that take a `sending T` parameter, store
459459
the value in a collection of `Disconnected<T>`, and later remove values from the
460-
collection and return them as `sendable T` results. This would allow some
460+
collection and return them as `sending T` results. This would allow some
461461
`AsyncSequence` types to return non-`Sendable` typed buffered elements as
462-
`sendable` without resorting to unsafe opt-outs in the implementation.
462+
`sending` without resorting to unsafe opt-outs in the implementation.
463463

464464
## Alternatives considered
465465

0 commit comments

Comments
 (0)