The suggestion of adding async / await to the language comes up with some frequency, with fibers being seen as a lackluster alternative.
Now, I feel like I must be missing something obvious, as fibers seem like the better option in almost every aspect to me. I'll compare them to async / await in .Net since that's the implementation I'm most familiar with.
The issues I have with a/a:
-
When a function wants to do something asynchronous every function up the call stack needs to be in on it. This is especially problematic with generic code and higher-order functions. Even with D's powerful metaprogramming facilities I don't see a way to handle this nicely. As an example: the whole IEnumerable / IAsyncEnumerable situation in .Net is a manifestation of this problem.
-
It messes up your callstack. This leads to problems with:
- Stack traces
- Debugging
- Memory dumps
- Sampling profilers
- And probably more that I haven't run into yet.
Now, some tooling can kinda sorta reconstruct a usable stack, but all the efforts I've seen so far are still harder to use than when you have a proper stack.
-
I don't like the Task<T> and await noise everywhere. It clutters up the code.
-
It's too easy to make a mistake and forget an await somewhere. Yes, an IDE will likely give a warning. No, I still don't like it ;)
-
It can put too much pressure on the GC. This won't be a problem when doing an HTTP request or something like that. It is a problem when there's an allocation for reading every single value in a DB query result.
All the above problems don't exist when using fibers. The only downside of fibers I'm aware of is that you have a full stack allocated for every fiber. This can cost a lot of (virtual) memory, but on the other hand it makes for very effective pooling. And if you're in a situation where this really is a problem you can tweak the stack size. Seems like a small price to pay to me.
Am I missing something? Thank you for your time.