I found this article very insightful around the async problem: <https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/>
> What language isn’t colored? > > [...] Three more languages that don’t have this problem: Go, Lua, and Ruby. > > Any guess what they have in common? > > Threads. Or, more precisely: multiple independent callstacks that can be > switched between. It isn’t strictly necessary for them to be operating system > threads. Goroutines in Go, coroutines in Lua, and fibers in Ruby are > perfectly adequate. Having used Lua a lot some time before, I can tell that it is very convenient to be able to write a function that at some points yields to another light thread. The threads are not running in parallel but you can have two processes with each their own stack passing values around to each other. It allows you to write algorithms differently. A bit like closure iterators in Nim. Every function in the language gets to be a closure iterator that can yield back the control to the calling light-thread (a main loop for example) and the calling thread can resume when convenient the paused thread. It's all implemented using setjmp/longjmp and effectively every function in the language can be async with no effort.
