I'm genuinely surpised to hear these suggestions, because my experiences have been exactly the opposite. I haven't yet encountered a situation where I've wanted some kind of stateless background type. But I have regularly found places where I have this one tiny bit of synchronous work that can be expensive and can and should be done off-actor. JSONDecoder is a fantastic, real-world example.
This is the critical concept.
I was just imagining what would happen if we made this change without the ability to annotate functions as @concurrent. I think it would introduce two problems (but please tell me if I'm missing something).
The least important is reducing reentrancy. I don't think this is something to panic about at all, but I do think it is a legimate compatibility concern.
But by far, the most important one is synchronous work now must block an actor. And, there's no good way to deal with this, because as far as I know, there's no other way to put work on the global executor. I agree with @sliemeobn that @noactor doesn't look great, but it does fit the concept.
But more and more, I'm not sure async functions have a problem at all. I think the problem is exclusively how to deal with synchronous work?
I think @Andrew_Hoos (and others!) are on to something about this being primarily a caller concern. I have aboslutely hit situations where waiting for some synchronous work was important. Sometimes you need to block the actor. Can I riff on his idea of modifying await, but make it look a little like defer?
let result = try await {
// this runs on the global executor
try nonIsolatedExpensiveWork()
}
Edit: I forgot about async let! Ok so there's an existing mechanism for handling this, maybe that's sufficient?