2 ms·
This is a worthwhile post, and I hope to have more to say about it soon. For now: It seems like we need some other terminology to refer to this group of issues,
by anonymoushn 5y ago
This is a worthwhile post, and I hope to have more to say about it soon. For now: It seems like we need some other terminology to refer to this group of issues, not the terminology that we use to refer to another much more annoying group of issues. This group of issues is similar to the group of issues you would face if you wanted to dynamically decide to call one of two functions with different signatures, and we don't generally say that language X has function colors because functions with different signatures must be called differently while language Y doesn't have function colors because it just fills in all the omitted values with `undefined` and drops extra arguments on the floor. In fact, we might criticize language Y for doing that, and here we could reasonably criticize Zig for even letting us store pointers to async and non-async functions in the same array of function pointers, given that they must be called differently.
As an aside, while Zig really does end up with some detectable differences between functions that are async and functions that are not, various other implementations of similar ideas like greenlet or Lua coroutines do not have these issues. The author maybe did not look into those implementations because they don't call themselves `async`, but this is a superficial detail. In Lua for example, `suspend` is written `coroutine.yield`, `resume` is written `coroutine.resume`, and `await` is written by calling `coroutine.resume` in a loop until the coroutine has errored or returned. The author could conduct a similar investigation of Lua coroutines and not run into any of the same issues because there really is only one calling convention in Lua (as far as call sites written in Lua are concerned, anyway). C primitives like ucontext_t or those exposed by libco also expose the same operations without introducing additional calling conventions.
The current system of calling conventions in Zig is imo somewhat troublesome because "async/not async" and "inlined/not inlined" should be independent concerns. This has caused some issues in my experience where using `suspend` to jump out of a search when a solution is found causes much worse codegen than the alternatives because the compiler ends up emitting many more distinct functions.
- gpderetta 5y agoI think calling lua style coroutines async is muddying the waters. Then even pthread could be called async. I think async should be reserved specifically for stackless coroutines runtimes.
- anonymoushn 5y agoZig has many similarities stackful coroutine runtimes though, and I suspect that our pre-existing notions of stackful and stackless coroutine libraries may not apply well to it. The compiler has to statically know the maximum depth from which a function or its callees can suspend, then this whole maximum-sized stack is saved in the resulting frame type. This is distinct from e.g. Rust, where each stack frame of the async parts of your async call stack has separate storage. Edit: I guess I mean to say that Zig could in the future remove the async calling convention (but keep the fact that each function is either async or not) and switch to a model like libco without breaking very much code. If this does happen, I don't think it's necessary to rename the keywords at that time.