Skip to content

Commit

Permalink
Reword and clarify per feedback.
Browse files Browse the repository at this point in the history
  • Loading branch information
simanerush committed Sep 11, 2024
1 parent 1bfd491 commit cc2f805
Showing 1 changed file with 37 additions and 6 deletions.
43 changes: 37 additions & 6 deletions proposals/NNNN-nonisolated-for-global-actor-cutoff.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,36 @@ For global-actor-isolated value types, [SE-0434: Usability of global-actor-isola

```swift
struct S {
nonisolated var x: Int // okay
var x: Int = 0 // okay ('nonisolated' is inferred within the module)
}

extension S: Equatable {
static nonisolated func ==(lhs: S, rhs: S) -> Bool {
return lhs.x == rhs.x // okay
}
}
```

In the above code, the value type `S` is implicitly `Sendable` because its storage `x` is of `Sendable` type `Int`. When `Sendable` value types are passed between isolation domains, each isolation domain has an independent copy of the value. Accessing stored properties of a value type from across isolation domains is safe as long as the stored property type is also `Sendable`. Even if the stored property is a `var`, assigning to the property will not risk a data race, because the assignment cannot have effects on copies in other isolation domains. Therefore, synchronized access to `x` in the example above is safe.
In the above code, the value type `S` is implicitly `Sendable` within the module and its storage `x` is of `Sendable` type `Int`. When `Sendable` value types are passed between isolation domains, each isolation domain has an independent copy of the value. Accessing properties stored on a value type from across isolation domains is safe as long as the stored property type is also `Sendable`. Even if the stored property is a `var`, assigning to the property will not risk a data race, because the assignment cannot have effects on copies in other isolation domains. Therefore, synchronous access of `x` from within the module is okay.

Additionally, [SE-0434](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0434-global-actor-isolated-types-usability.md) allows explicitly annotating globally-isolated value types' properties such as `x` in the previous example with `nonisolated` for synchronous access from outside the module. This proposal extends this rule to **all** `Sendable` value types:

```swift
// In Module A
public struct S: Sendable {
nonisolated public var x: Int // okay
}

// In Module B
import A

actor MyActor {
func test() {
var s = S()
s.x += 1 // concurrent, synchronous access is okay.
}
}
```

### 5. Classes, structs, and enums

Expand Down Expand Up @@ -224,23 +249,27 @@ The above behavior is semantically consistent with the existing rules around glo

Additionally, we propose the following set of rules for when the `nonisolated` attribute **cannot** be applied:

* Along with some other isolation such as a global actor or an isolated parameter:
#### Along with some other isolation such as a global actor or an isolated parameter:

```swift
@MainActor
nonisolated struct Conflict {} // error: 'struct 'Conflict' has multiple actor-isolation attributes ('nonisolated' and 'MainActor')'
```

* On a property of a `Sendable` type when the type of the property does not conform to `Sendable`:
The above code is invalid because the `Conflict` struct cannot simultaneously opt-out of isolation and declare one.

#### On a property of a `Sendable` type when the type of the property does not conform to `Sendable`:

```swift
@MainActor
struct InvalidStruct /* implicitly Sendable */ {
nonisolated let test: NonSendable // error: 'nonisolated' can not be applied to variable with non-'Sendable' type 'NonSendable
nonisolated let x: NonSendable // error: 'nonisolated' can not be applied to variable with non-'Sendable' type 'NonSendable
}
```

* On a property of a `Sendable` class when the property is a var:
In the above code, `InvalidStruct` is `Sendable`, allowing it to be sent across the concurrency domains. The property `x` is of `NonSendable` type, and if declared `nonisolated`, it would be allowed to be accessed from outside the main actor domain that `InvalidStruct` is isolated to, thus contradicting its lack of `Sendable` capability.

#### On a property of a `Sendable` class when the property is a var:

```swift
@MainActor
Expand All @@ -249,6 +278,8 @@ final class InvalidClass /* implicitly Sendable */ {
}
```

In this example, `InvalidClass` is a `Sendable` reference type, which allows concurrent synchronous access to `test` since it is `nonisolated`. This introduces a potential data race.

## Source compatibility

None, this is an additive change to the concurrency model.
Expand Down

0 comments on commit cc2f805

Please sign in to comment.