Hello,
What does the community wisdom think about async functions that return the result of an input closure? Should the result type be constrained to Sendable, or not?
// No constraint
public func makeValue<T>(
_ value: @escaping @Sendable () -> T
) async -> T
// Sendable constraint
public func makeValue<T: Sendable>(
_ value: @escaping @Sendable () -> T
) async -> T
It is assumed that the function can be written without Sendable constraint, which means, AKAIK, that it does not introduce any suspension point before returning the result of its input closure.
At first sight, it looks like the better variant is the one without any constraint. The user will just make the type Sendable if needed by their code:
func run() async {
let value = await makeValue { ... }
print(value) // Sendable not needed, lucky you!
await actor.use(value) // Sendable needed, deal with it.
}
(I hope I'm correct).
Also, I'm still confused by continuations. When the value is "returned" via an UnsafeContinuation.resume
, no suspension point is introduced, and the compiler does not warn if T
is not sendable. Can I indeed assume that the value won't cross isolation domains before it ends in the hands of the caller? (if I interpret correctly @John_McCall in [Pitch] Synchronous Mutual Exclusion Lock - #55 by John_McCall)
Finally, there are a lot of pitches and advances about isolation parameters and regions, which aim to ease the use of non-Sendable types.
In the end, I'm on the side of NOT constraining the input type. Are there other considerations that I should think about?