[Pitch][SerialExecutor] Improved Custom SerialExecutor isolation checking

Hi everyone,
there's a few concurrency improvements queued up, and this is one last piece of the puzzle I'm working on currently.

This proposal introduces a new func isIsolatingCurrentContext() -> Bool protocol requirement for SerialExecutor that is going to make errors surfaced by the concurrency runtime when isolation violations occur more understandable (by including more information about the expected vs. current executor / actor etc).

This proposal builds on the basis of SE-0424: Custom isolation checking for SerialExecutor, which introduced the func checkIsolated() -> Void function, but offers a more flexible method that does not have to crash but can return true/false instead.

The proposal should not have much impact on day-to-day developers because it only affects how custom executors are implemented, and we'll take care to implement it properly on those that we can.

End-user visible changes this proposal will enable:

  • better error reporting on dynamic isolation failures in the future (as in, including the "current" executor details in addition to the "expected" one in failures)
  • ability to issue isolation violation warnings by libraries which want to take adoption of strict mode carefully and give users some time of warnings before they enable a strict checking mode; whereas this was impossible with custom executors with the previous APIs.

Please read the pitch over here: Improved Custom SerialExecutor isolation checking for Concurrency Runtime

The pitch also includes a detailed diagram explaining how we compare executors in order to determine if something is "isolated by" some executor, which you may find quite informative:


Please send in editorial fixes right onto the pull requests (you can comment on it): [Concurrency] isIsolatingCurrentContext - Improved Custom SerialExecutor isolation checking by ktoso ยท Pull Request #2716 ยท swiftlang/swift-evolution ยท GitHub and provide feature discussion in the pitch thread here.

I'm especially interested in feedback from developers who have implemented their custom executors that are not using dispatch as the underlying scheduling mechanism. And I'm also open to naming discussions.

Thanks in advance!

3 Likes

Another notable reason for this API from the SE-0424 review thread:

As SE-0424 argued, not every implementation can provide an implementation that can give an definitive yes/no answer. Then shouldn't return type be Optional<Bool>? Could Optional<Bool> also help to avoid new initializer signature?

Yeah, avoiding yet another marker initializer would be nice, I really don't like that part of the idea currently.

If we're doing a three-state we could proably name it explicitly:

  • unknownCheckIsolated -> IDK, call checkIsolated
  • isolated -> OK, do not call checkIsolated
  • nonisolated -> FAIL, form failure message in Swift runtime

or something like that. Or yeah overload the meaning of nil...

The problem with that is that we'd be doing more calls into Swift from the runtime which can add up if this is called from tight code... So that's also something to think about :thinking: I can do some measurements here once I get an implementation going.