So no, go coroutines (or any stack full coroutines) are actually more powerful than thise exposed in other languages.
It's not a common feature. Usually it's present in a language that has "continuations" and the api is something dreadful like call/cc. But you can use it in Lua with the above mentioned patch, and you can use it in byuu/co with memcpy.
call/cc answers: "The new execution context should begin executing and the old one should be bound to a local variable, no, one"
As a person who occasionally explains these things to people who have never been exposed to them, I strongly prefer: "The old execution context should continue executing and the new one should be bound to a local variable, yes, as many as we need to produce the preceding answers"
I think without trying too hard you can get the number of primitives in the latter case down to three, "create", "copy", and "switch." If you wanted to bug your users you could get it down to two.
Do you have an example of what you have in mind so we can see more clearly what it is about?
Say you want to take a snapshot of where your program is, run the code some more, and then later on restore execution back to that snapshot.
In the parlance of video games and emulators, this would mean save states. You could use these save states to implement speculative execution to eg remove input latency from games using a method called run-ahead [2].
With state machines, this is trivial: just record all the state machine variables. With coroutines / cooperative threading, it's not: the state is all stored on the stack frame.
My stackful coroutine library can do this by essentially memcpy'ing the stack frames themselves, but it comes with some seriously negative caveats: the biggest is you can't save this to disk, because on the next program run, ASLR, etc would invalidate the pointers in the stack frame. In fact, you can't even safely release and allocate new memory between a serialize and unserialize point, or the stack frames may have dangling pointers in them. In practice, this is acceptable and workable for features like real-time rewind and run-ahead.
Library support for C++ coroutine serialization would be trivial since they are stackless. Getting around the limitations I mentioned for stackful coroutines would be immensely more challenging.
Challenging but it's definitely been done before. The system below [1] (disclosure: I worked on it years ago), stores every memory write in a separate buffer on the assembly level. You need to modify the compiler for this, and it cuts performance roughly in half, but it allows you to step backwards in code and perform sophisticated performance analysis.
It's still doable, and it's definitely worth doing, but I understand the uses I've mentioned are rather niche, so it's unlikely to occur. For one, we still don't have built-in stackful coroutine support even in C++20.
Yes, it's not for the average developer. Yet it should be incumbent on the tools builders. I'm actually surprised that most compilers/interpreters don't have a "step backwards" flag that you can turn on during compile/run-time. It would be a helpful feature to expert and novice developers alike, but hasn't really caught on outside of niche areas.
N:M threading from 1999!
And there are many more recent examples too.
There is no parallelism whatsoever in GNU Pth.
You only get a single kernel thread and "green" userland threads cooperatively scheduled on top of that single kernel thread.
That's it.
Not sure if that helps the argument that this has been around for "years" (since it's still in the experimental directory), but I guess there were some libraries trying to accomplish this.
https://github.com/facebook/folly/tree/master/folly/experime...