File: sendable-metatypes.md

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (62 lines) | stat: -rw-r--r-- 2,062 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# Sendable metatypes

Types that are shared in concurrent code generally need to conform to `Sendable`. The same is true in generic code when sharing parameters of a generic parameter `T`. For example, the given code will produce an error under strict concurrency checking

```swift
func doSomethingElsewhere<T>(_ value: T) {
  Task { @concurrent in
    print(value) // warning: capture of non-Sendable type 'T'
  }
}
```

because `value` can have a non-Sendable type that is not safe to share. To address this potential data race, the type `T` can be marked as `Sendable`:

```swift
func doSomethingElsewhere<T: Sendable>(_ value: T) {
  Task { @concurrent in
    print(value)
  }
}
```

The same issue can occur when passing the type `T` itself, rather than a value of type `T`. The compiler will indicate such problems by noting that the metatype of `T`, spelled `T.Type`, is not `Sendable`:

```swift
protocol P {
  static func doSomething()
}

func doSomethingStatic<T: P>(_: T.Type) {
  Task { @concurrent in
    T.doSomething() // warning: capture of non-Sendable type 'T.Type' in an isolated closure
  }
}
```

In these cases, the type parameter should be required to conform to the `SendableMetatype` protocol, e.g.,

```swift
func doSomethingStatic<T: P & SendableMetatype>(_: T.Type) {
  Task { @concurrent in
    T.doSomething()
  }
}
```

The `SendableMetatype` requirement allows the function to share the type `T` in concurrent code. To maintain data race safety, it prevents callers from using isolated conformances in the call. For example, the following code will be rejected due to a data race:

```swift
@MainActor
class C: @MainActor P {
  static func doSomething() { }
}

@MainActor
func test(c: C) {
  doSomethingStatic(C.self) // error: main actor-isolated conformance of 'C' to 'P' cannot satisfy conformance requirement for a 'Sendable' type parameter
}

```

The conformance of `C` to `P` can only be used on the main actor, so it cannot be provided to `doSomethingStatic`, which calls the conformance from a different concurrent task.