New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@isolated(any)
function types
#2357
Conversation
tasks: | ||
- `Task.init` | ||
- `Task.detached` | ||
- `TaskGroup.add` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the other proposal I wrote I guess; if we want to list them all, we have to list them all:
- `TaskGroup.add` | |
- `TaskGroup.addTask(UnlessCancelled)` |
(or, just say "all")
- `Task.init` | ||
- `Task.detached` | ||
- `TaskGroup.add` | ||
- `ThrowingTaskGroup.add` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- `ThrowingTaskGroup.add` | |
- `ThrowingTaskGroup.addTask(UnlessCancelled)` |
- `Task.detached` | ||
- `TaskGroup.add` | ||
- `ThrowingTaskGroup.add` | ||
- `DiscardingTaskGroup.add` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- `DiscardingTaskGroup.add` | |
- `DiscardingTaskGroup.addTask(UnlessCancelled)` |
- `TaskGroup.add` | ||
- `ThrowingTaskGroup.add` | ||
- `DiscardingTaskGroup.add` | ||
- `ThrowingDiscardingTaskGroup.add` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- `ThrowingDiscardingTaskGroup.add` | |
- `ThrowingDiscardingTaskGroup.addTask(UnlessCancelled)` |
The Throwing...
technically shall become deprecated/removed if we manage to make typed throws happen for them 🤔 There's another proposal in flight for this
Swift reserves the right to optimize the execution of tasks to avoid | ||
"unnecessary" isolation changes, such as when an isolated `async` function | ||
starts by calling a function with different isolation. In general, this | ||
includes optimizing where the task initially starts executing. As an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably worthy of an example as that's the "we'll reorder things" case that people should watch out for.
Maybe a bit here?
includes optimizing where the task initially starts executing. As an | |
includes optimizing where the task initially starts executing: | |
```swift | |
@MainActor class Helper { | |
let other: OtherActor | |
func help() { | |
Task { await other.work() } // *implicitly* starts on MainActor, however | |
Task { await other.work() } // this may be optimized away and start on `other` immediately | |
} | |
\``` // FIXME: can't suggest change with a \``` inside it, remove the \ | |
In this example, `Task` is implicitly inheriting the enclosing context's MainActor isolation, however the task immediately calls code on another actor. The Swift runtime reserves the right to optimize away the initial "starting the task" enqueue on the MainActor, and instead enqueue on the `other` immediately. | |
As an |
Did I get the semantics right of what you're proposing here?
task function is explicitly isolated to an actor (or is not a closure).
PRs implementing the feature.
closure isolation controls, which will not be finished before we review this proposal.
0d71b2c
to
9ee7977
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good; just a handful of comments.
- It can also be inferred from context in a number of ways, such as | ||
if the function is a method of a type with that attribute (which | ||
itself can be inferred in a number of ways). | ||
- Additionally, a closure passed directly to the `Task` initializer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A small drafting suggestion: the bullets here are interspersing the kinds of isolation with the ways in which isolation is inferred, making it harder to keep both separate in the reader's mind. Perhaps lay out the kinds of isolation here, and move the "inference" bits until later?
closure expression (including an implicit autoclosure), a function | ||
reference, or a partial application of a method reference, the | ||
resulting function is dynamically isolated to the isolation of the | ||
function or closure. This looks through non-instrumental differences |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"non-instrumental differences" isn't a phrase I've ever seen us use. Perhaps "looks though syntax that has no effect on the semantics of the expression, such as parentheses"?
- it is a reference to a capture or immutable binding immediately | ||
initialized with a derivation of `E`; or |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, the current isolation analysis for isolated parameters does not look through an "immutable binding immediately initialized with a derivation of E
", e.g.,
actor A {
func g() { }
}
func f(actor: isolated A) {
let a = actor
a.g() // error: a is not considered to be in the same isolation domain, call needs to be asynchronous
}
If we want to generalize that, great, but we should do so consistently rather than make it a rule specific to .isolation
on an @isolated(any)
type.
|
||
(This uses the `isolated` capture modifier proposed in the draft | ||
[closure isolation control][isolated-captures] proposal. It would be | ||
possible but significantly more awkward to get this effect with that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
possible but significantly more awkward to get this effect with that | |
possible but significantly more awkward to get this effect without that |
- it comes from a closure expression that is only *implicitly* isolated | ||
to an actor (that is, it has neither an explicit `isolated` capture | ||
nor a global actor attribute). This can currently only happen with | ||
`Task {}`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This came up in the pitch thread, and you answered it there. The proposal would be stronger if it included this justification.
with the closure isolation pitch. We're considering this proposal knowing that some things can't be expressed yet without that pitch. As long as we add something vaguely like that pitch in the future, this is how the rules for isolated(any) should apply to it.
No description provided.