I've noticed quite a lot of confusion between @isolated(any) and @_inheritActorContext. Because they are used together by Task, but the underscored attribute is not visible in documentation, many people reach the conclusion that the isolation inheritance actually comes from @isolated(any).
And lately, this has got me thinking. I'm having a hard time coming up with real problems that are only solvable by one but not the other. Are there any?
This is particularly relevant for Closure isolation control, because that proposal would make isolation inheritance public and easier tool to use. It seems like the only motivation for this is a path to change the sematics around capturing isolation.
This is a round-about way of me contemplating fusing these two concepts into one. I like the idea of simplying the language in this way, but I'm having trouble figuring out if this is safe and/or reasonable thing to do.
I agree that these two attributes are easy to confuse, especially with @_inheritActorContext not having been formalized / hidden from documentation / etc, but @_inheritActorContext and @isolated(any) have different effects.
@isolated(any) allows you to recover the isolation of a function value as an (any Actor)? value. It has no impact on the inferred isolation of a closure whose type includes @isolated(any), and that's where I think people get confused. If you take @isolated(any) away, isolation inference behaves exactly the same way. For non-@Sendable/sending closures, isolation is already effectively "inherited" from the enclosing context where the closure is formed.
@_inheritActorContext is only useful when you have a closure that either @Sendable or passed to a sending parameter, and it applies the same isolation inference behavior that you would get if that closure didn't have those other concurrency annotations.
I think the need for @isolated(any) is fairly rare; the task creation APIs use the isolation value to enqueue the operation directly on the isolated actor to resolve the issue that tasks always (used to) begin on the generic executor. That problem wasn't caused by closures having the wrong static isolation, it was because the implementation of the task creation APIs didn't have the actor value to enqueue on.