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
@@ -28,11 +29,11 @@ When referencing a method *without* partially applying it to the object instanc
28
29
29
30
30
31
```
31
-
let unapplied:(T) -> (() -> Void) = S.f
32
+
let unapplied:(T) -> (() -> Void) = S.f
32
33
```
33
34
34
35
35
-
Suppose we want to create a generic method that expects an unapplied function method conforming to Senable as a parameter. We can create a protocol ``P`` that conforms to the `Sendable` protocol and tell our generic function to expect some generic type that conforms to ``P``. We can also use the `@Sendable` attribute, introduced for closures and functions in [SE-302](https://github.com/kavon/swift-evolution/blob/sendable-functions/proposals/0302-concurrent-value-and-concurrent-closures.md), to annotate the closure parameter.
36
+
Suppose we want to create a generic method that expects an unapplied function method conforming to Sendable as a parameter. We can create a protocol ``P`` that conforms to the `Sendable` protocol and tell our generic function to expect some generic type that conforms to ``P``. We can also use the `@Sendable` attribute, introduced for closures and functions in [SE-302](https://github.com/kavon/swift-evolution/blob/sendable-functions/proposals/0302-concurrent-value-and-concurrent-closures.md), to annotate the closure parameter.
36
37
37
38
38
39
```
@@ -74,6 +75,8 @@ This is a lot of churn to get the expected behavior. The compiler should preserv
74
75
75
76
## Proposed solution
76
77
78
+
We propose the compiler should automatically employ `@Sendable` to functions that cannot capture non-Sendable states. This includes partially-applied and unapplied instance methods of `Sendable` types, as well as non-local functions. Additionally, it should be disallowed to utilize `@Sendable` on instance methods of non-`Sendable` types.
79
+
77
80
For a function, the `@Sendable` attribute primarily influences the kinds of values that can be captured by the function. But methods of a nominal type do not capture anything but the object instance itself. Semantically, a method can be thought of as being represented by the following functions:
@@ -104,25 +108,27 @@ type NominalType : Sendable {
104
108
}
105
109
```
106
110
107
-
For example, by declaring the following type `Sendable`, the partial and unapplied function values of the type would have implied Sendabilty and the following code would compile with no errors.
108
-
111
+
For example, by declaring the following type `Sendable`, the partial and unapplied function values of the type would have implied Sendability and the following code would compile with no errors.
let partial : @Sendable (String, String) → Void = User().changeAddress // no error
146
152
```
147
153
148
-
The next few are:
154
+
These two rules include partially applied and unapplied static methods but do not include partially applied or unapplied mutable methods. Unapplied references to mutable methods are not allowed in the language because they can lead to undefined behavior. More details about this can be found in [SE-0042](https://github.com/apple/swift-evolution/blob/main/proposals/0042-flatten-method-types.md).
155
+
156
+
Next is:
149
157
150
-
1. The inference of `@Sendable` when referencing non-local functions.
158
+
3. The inference of `@Sendable` when referencing non-local functions.
151
159
152
-
Unlike closures, which retain the captured value, global functions can't capture any variables - because global variables are just referenced by the function without any ownership. With this in mind there is no reason not to make these, Sendable by default.
160
+
Unlike closures, which retain the captured value, global functions can't capture any variables - because global variables are just referenced by the function without any ownership. With this in mind there is no reason not to make these`Sendable` by default. This change will also include static global functions.
153
161
154
162
```
155
163
func doWork() -> Int {
156
-
`Int.random(in: 1..<42)`
164
+
` Int.random(in: 1..<42)`
157
165
}
158
166
159
167
Task<Int, Never>.detached(priority: **nil**, operation: doWork) // Converting non-sendable function value to '@Sendable () async -> Void' may introduce data races
160
168
```
161
169
162
170
Currently, trying to start a `Task` with the global function `doWork` will cause an error complaining that the function is not `Sendable`. This should compile with no issue.
163
171
164
-
1. Prohibition of marking methods `@Sendable` when the type they belong to is not `@Sendable`.
165
-
1. class C {
166
-
var random: Int = 0 // random is mutable so `C` can't be checked sendable
167
-
168
-
@Sendable func generateN() async -> Int { //error: adding @Sendable to function of non-Senable type prohibited
169
-
random = Int.random(in: 1..<100)
170
-
return random
171
-
}
172
-
}
172
+
4. Prohibition of marking methods `@Sendable` when the type they belong to is not `@Sendable`.
173
+
```
174
+
class C {
175
+
var random: Int = 0 // random is mutable so `C` can't be checked sendable
173
176
174
-
Task.detached {
175
-
let num = C()
176
-
let n = await num.generateN()
177
-
num.random = 42 // accessing the `random` var while generateN is mutating it
177
+
@Sendable func generateN() async -> Int { //error: adding @Sendable to function of non-Senable type prohibited
178
+
random = Int.random(in: 1..<100)
179
+
return random
178
180
}
179
-
2. If we move the previous work we wanted to do into a class that stores the random number we generate as a mutable value, we could be introducing a data race by marking the function responsible for this work `@Sendable` . Doing this should be prohibited by the compiler.
181
+
}
182
+
183
+
func test(c: C) { c.generateN() }
180
184
181
-
Since `@Sendable` attribute will be automatically determined with this proposal, you don’t have to explicitly write it on function declarations.
185
+
let num = C()
186
+
Task.detached {
187
+
test(num)
188
+
}
189
+
test(num) // data-race
190
+
```
191
+
192
+
If we move the previous work we wanted to do into a class that stores the random number we generate as a mutable value, we could be introducing a data race by marking the function responsible for this work `@Sendable` . Doing this should be prohibited by the compiler.
193
+
194
+
Since `@Sendable` attribute will be automatically determined with this proposal, you will no longer have to explicitly write it on function and method declarations.
182
195
183
196
## Source compatibility
184
197
185
198
No impact.
186
199
187
200
## Effect on ABI stability
188
201
189
-
This would impact the mangling of function names.
202
+
When you remove an explicit `@Sendable` from a method, the mangling of that method will change. Since `@Sendable` will now be inferred, if you choose to remove the explicit annotation to "adopt" the inference, you may need to consider the mangling change.
190
203
191
204
## Effect on API resilience
192
205
@@ -201,12 +214,8 @@ Accessors are not currently allowed to participate with the `@Sendable` system i
201
214
Swift could forbid explicitly marking function declarations with the` @Sendable` attribute, since under this proposal there’s no longer any reason to do this.
202
215
203
216
```
204
-
/***@Sendable*/** func alwaysSendable() {}
217
+
/*@Sendable*/ func alwaysSendable() {}
205
218
```
206
219
207
220
However, since these attributes are allowed today, this would be a source breaking change. Swift 6 could potentially include fix-its to remove `@Sendable` attributes to ease migration, but it’d still be disruptive. The attributes are harmless under this proposal, and they’re still sometimes useful for code that needs to compile with older tools, so we have chosen not to make this change in this proposal. We can consider deprecation at a later time if we find a good reason to do so.
0 commit comments