Hacker News new | ask | show | jobs
by devbug 2686 days ago
As someone in the midst of building a game in C for 7 platforms, with WebAssembly being one of them, my main disappointment is with the lack of coroutines (or lack of control over the stack to implement them.) It hinders how wide my engine can go since I'm limited to a fork-and-join model for splitting work across threads. Poor code generation is also another pain point, but I fully expect that to improve drastically over the coming year.

Overall, I'm pretty excited for WASM and the implications of it, but it does feel like the web has regressed in the ability to deliver games.

2 comments

Most common coroutine implementations, such as JavaScript's and Python's, are delimited or "symmetric". This means the most obvious implementation is in terms of compiler transformations in the source language. It seems out of WASM's scope to do this.

Undelimited "asymmetric" coroutines, like Lua's, could be an interesting addition. That still seems to me to be too high level a feature for a "portable assembly language" specification though.

I think you might be conflating characteristics regarding delimited and symmetric coroutines. But let's step back.

JavaScript's and Python's choice of coroutine styles was constrained and effectively dictated by runtime limitations. CPython, V8, and similar implementations mix their C and assembly callstacks with their logical language callstacks. Because the host runtimes didn't readily support multiple stacks without a complete rewrite, this bled into the language runtime. There was a path dependency whereby early implementation choices directed the evolution of the language semantics.

WASM is recapitulating the same cycle. Which is understandable because time is limited and you can't make the perfect the enemy of the good, but you still have to recognize it for what it is--a vicious cycle of short sightedness. If WASM doesn't provide multiple stacks as a primitive resource, then things like stackful coroutines, fibers, etc, will have to be emulated (at incredible cost, given WASM's other constraints regarding control flow). And if they have to be emulated they'll be slow, which means languages will continue avoiding them.

I agree that CPython and V8 omitting the ability to juggle multiple stacks is a mistake. For higher-level languages, undelimited coroutines or continuations allow for very useful abstractions like Go's and Erlang's transparently non-blocking IO.

However, it doesn't seem to be _entirely_ an implementation detail. Some developers just don't seem to like the semantics of called functions being able to cooperatively yield without the caller explicitly opting into it with a keyword like `await`. I disagree with them, but it's a legitimate complaint I've a few times.

It reminds me of arguments in the Lisp community about delimited continuations and undelimited, i.e. Common Lisp and Scheme. A lot of the arguments there are really about semantics and not implementation details, and come to the same point: should cooperative scheduling require explicit notation at each level of the call stack?

My view on this is that systems languages like C and Rust should require explicit notation for it whereas application languages should not. This seems to be a point in favour of Go and Erlang over Java and C#.

However WASM, similar to C or Rust, seems to target a level in the tech stack at which it should concern itself only with abstractions that have relatively direct translations to the instruction set of the underlying hardware. Support for multiple stacks doesn't fit into this from what I can see. (A similar argument can be made for WASM not supporting garbage collection too, although it looks like that'll be added at some point to make interoperability with JS smoother.)

With the JVM supposedly adding fibres soon, it poses a question for WASM: is it trying to be a portable assembly language, a portable high-level language runtime, or something in between?

The inability to implement coroutines is addressed in the second article in the series here http://troubles.md/posts/why-do-we-need-the-relooper-algorit...