Why doesn't unstructured task Task { } require explicit use of self?
My understanding (could be wrong):
Both unstructured task Task { ... } and detached task Task.detached { ... } both run asynchronously and may outlive the function from which it is called.
Both could cause data race when used in non-isolated function
Code
class Car {
var price = 100
func f1() {
Task {
price = price + 1 //Why doesn't property `price` not require explicit of use of self? wouldn't this run asynchronously?
}
Task.detached {
// price = price + 1 //Error: Reference to property 'price' in closure requires explicit use of 'self' to make capture semantics explicit
}
}
}
The closure is marked with @_implicitSelfCapture with the idea that the task will eventually complete, releasing captured objects. Some question that here Explicit self not required for Task closures?
The intent behind requiring self. when capturing self in an escaping closure is to warn the developer about potential reference cycles. The closure passed to Task is executed immediately, and the only reference to self is what occurs in the body. Therefore, the explicit self. isn't communicating useful information and should not be required.
But next here is:
Note: The same applies to the closure passed to Task.detached and TaskGroup.addTask .
But detached Task closure is escaping operation: @escaping @Sendable () async -> Success
I think the documentation in the footnote is outdated
I think detached task initially wasn't required to explicitly mention self but was later changed.
Questions
Does detached task have a self requirement because of how it interacts with actors (it doesn't inherit the context and could run on a different executor)?
Is there a way to reliably detect data races? TSAN sometimes catches it and sometimes seems to miss data races. (not sure others face this issue or I am missing something)