Skip to content

Commit aa7ee30

Browse files
committed
WIP
1 parent 8991630 commit aa7ee30

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Default actor isolation typealias
2+
3+
* Proposal: [SE-NNNN](NNNN-default-isolation-typealias.md)
4+
* Authors: [Holly Borla](https://github.com/hborla)
5+
* Review Manager: TBD
6+
* Status: **Awaiting review**
7+
* Vision: [Improving the approachability of data-race safety](/visions/approachable-concurrency.md)
8+
* Implementation: [swiftlang/swift#80572](https://github.com/swiftlang/swift/pull/80572)
9+
* Experimental Feature Flag: `DefaultIsolationTypealias`
10+
* Previous Proposal: [SE-0466: Control default actor isolation inference][SE-0466]
11+
* Review: ([pitch](https://forums.swift.org/...))
12+
13+
## Introduction
14+
15+
[SE-0466: Control default actor isolation inference][SE-0466] introduced the ability to specify default actor isolation on a per-module basis. This proposal introduces a new typealias for specifying default actor isolation in individual source files within a module. This allows specific files to opt out of main actor isolation within a main-actor-by-default module, and opt into main actor isolation within a nonisolated-by-default module.
16+
17+
## Motivation
18+
19+
SE-0466 allows code to opt in to being “single-threaded” by default by isolating everything in the module to the main actor. When the programmer really wants concurrency, they can request it explicitly by marking a function or type as `nonisolated`, or they can define it in a module that does not default to main-actor isolation. However, it's very common to group multiple declarations used in concurrent code into one source file or a small set of source files. Instead of choosing between writing `nonisolated` on each individual declaration or splitting those files into a separate module, it's desirable to state that all declarations in those files default to `nonisolated`.
20+
21+
## Proposed solution
22+
23+
This proposal allows writing a private typealias named `DefaultIsolation` to specify the default actor isolation for a file.
24+
25+
An underlying type of `MainActor` specifies that all declarations in the file default to main actor isolated:
26+
27+
```swift
28+
// main.swift
29+
30+
private typealias DefaultIsolation = MainActor
31+
32+
// Implicitly '@MainActor'
33+
var global = 0
34+
35+
// Implicitly '@MainActor'
36+
func main() { ... }
37+
38+
main()
39+
```
40+
41+
An underlying type of `nonisolated` specifies that all declarations in the file default to `nonisolated`:
42+
43+
```swift
44+
// Point.swift
45+
46+
private typealias DefaultIsolation = nonisolated
47+
48+
// Implicitly 'nonisolated'
49+
struct Point {
50+
var x: Int
51+
var y: Int
52+
}
53+
```
54+
55+
## Detailed design
56+
57+
A typealias named `DefaultIsolation` can specify the actor isolation to use for the source file it's written in under the following conditions:
58+
59+
* The typealias is written at the top-level.
60+
* The typealias is `private` or `fileprivate`; the `DefaultIsolation` typealias cannot be used to set the default isolation for the entire module, so its access level cannot be `internal` or above.
61+
* The underlying type is either `MainActor` or `nonisolated`.
62+
63+
It is not invalid to write a typealias called `DefaultIsolation` that does not meet the above conditions. Any typealias named `DefaultIsolation` that does not meet the above conditions will be skipped when looking up the default isolation for the source file. The compiler will emit a warning for any `DefaultIsolation` typealias that is not considered for default actor isolation along with the reason why:
64+
65+
```swift
66+
@globalActor
67+
actor CustomGlobalActor {
68+
static let shared = CustomGlobalActor()
69+
}
70+
71+
private typealias DefaultIsolation = CustomGlobalActor // warning: not used for default actor isolation
72+
```
73+
74+
To allow writing `nonisolated` as the underlying type of a typealias, this proposal adds an empty type named `nonisolated` to the Concurrency library:
75+
76+
```swift
77+
public struct nonisolated {}
78+
```
79+
80+
This type serves no purpose beyond specifying default actor isolation.
81+
82+
## Source compatibility
83+
84+
Technically source breaking if someone happens to have written a private `DefaultIsolation` typealias with an underlying type of `MainActor`, which will start to infer every declaration in that file as `@MainActor`-isolated after this change. This seems extremely unlikely.
85+
86+
## ABI compatibility
87+
88+
This proposal has no ABI impact on existing code.
89+
90+
## Implications on adoption
91+
92+
This proposal does not change the adoption implications of adding `@MainActor` to a declaration that was previously nonisolated and vice versa. The source and ABI compatibility implications of changing actor isolation are documented in the Swift migration guide's [Library Evolution](https://github.com/apple/swift-migration-guide/blob/29d6e889e3bd43c42fe38a5c3f612141c7cefdf7/Guide.docc/LibraryEvolution.md#main-actor-annotations) article.
93+
94+
## Alternatives considered
95+
96+
Adding an empty type named `nonisolated` to the Concurrency library to enable writing it as the underlying type of a typealias is pretty weird, but I felt this was the simplest option that preserved a consistent way to spell `nonisolated`. There are a number of alternatives, including:
97+
98+
* Using a bespoke syntax such as `using MainActor` and `using nonisolated`.
99+
* Capitalizing the `Nonisolated` type.
100+
* Using `Never` instead of a new empty type to represent `nonisolated`.
101+
* Allow writing a keyword such as `nonisolated` or `nil` as the underlying type of a typealias.
102+
103+
The benefits of the typealias model include:
104+
105+
* It's consistent with other similar defaulting rules such as the default literal types and default actor system types.
106+
* It does not require adding any new syntax.
107+
* The lookup rules for computing default isolation are very straightforward.
108+
109+
Having a `nonisolated` type may also allow us to improve the package manifest APIs for specifying default isolation, allowing us to move away from using `nil` to specify `nonisolated`:
110+
111+
```swift
112+
SwiftSetting.defaultIsolation(nonisolated.self)
113+
```
114+
115+
We can also pursue allowing bare metatypes without `.self` to allow:
116+
117+
```swift
118+
SwiftSetting.defaultIsolation(nonisolated)
119+
SwiftSetting.defaultIsolation(MainActor)
120+
```
121+
122+
[SE-0466]: /proposals/0466-control-default-actor-isolation.md

0 commit comments

Comments
 (0)