Discussion
Looking at Unity finally made me understand the point of C++ coroutines
cherryteastain: Not an expert in game development, but I'd say the issue with C++ coroutines (and 'colored' async functions in general) is that the whole call stack must be written to support that. From a practical perspective, that must in turn be backed by a multithreaded event loop to be useful, which is very difficult to write performantly and correctly. Hence, most people end up using coroutines with something like boost::asio, but you can do that only if your repo allows a 'kitchen sink' library like Boost in the first place.
spacechild1: ASIO is also available outside of boost! https://github.com/chriskohlhoff/asio
abcde666777: More broadly the dimension of time is always a problem in gamedev, where you're partially inching everything forward each frame and having to keep it all coherent across them.It can easily and often does lead to messy rube goldberg machines.There was a game AI talk a while back, I forget the name unfortunately, but as I recall the guy was pointing out this friction and suggesting additions we could make at the programming language level to better support that kind of time spanning logic.
pjc50: Always jarring to see how Unity is stuck on an ancient version of C#. The use of IEnumerable as a "generator" mechanic is quite a good hack though.
repelsteeltje: Not too different from C++'s iterator interface for generators, I guess.
repelsteeltje: > There was a game AI talk a while back, I forget the name unfortunately, but as I recall the guy was pointing out this friction and suggesting additions we could make at the programming language level to better support that kind of time spanning logic.Sounds interesting. If it's not too much of an effort, could you dig up a reference?
debugnik: Not that ancient, they just haven't bothered to update their coroutine mechanism to async/await. The Stride engine does it with their own scheduler, for example.
tyleo: Unity is currently on C# 9 and that IEnumerable trick is no longer needed in new codebases. async is properly supported.
nananana9: You can roll stackful coroutines in C++ (or C) with 50-ish lines of Assembly. It's a matter of saving a few registers and switching the stack pointer, minicoro [1] is a pretty good C library that does it. I like this model a lot more than C++20 coroutines:1. C++20 coros are stackless, in the general case every async "function call" heap allocates.2. If you do your own stackful coroutines, every function can suspend/resume, you don't have to deal with colored functions.3. (opinion) C++20 coros are very tasteless and "C++-design-commitee pilled". They're very hard to understand, implement, require the STL, they're very heavy in debug builds and you'll end up with template hell to do something as simple as Promise.all[1] https://github.com/edubart/minicoro
pjc50: > You can roll stackful coroutines in C++ (or C) with 50-ish lines of AssemblyI'm not normally keen to "well actually" people with the C standard, but .. if you're writing in assembly, you're not writing in C. And the obvious consequence is that it stops being portable. Minicoro only supports three architectures. Granted, those are the three most popular ones, but other architectures exist.
lionkor: For anyone wondering; this isn't a hack, that's the same library, just as good, just without boost dependencies.
pjc50: Much of the original motivation for async was for single threaded event loops. Node and Python, for example. In C# it was partly motivated by the way Windows handles a "UI thread": if you're using the native Windows controls, you can only do so from one thread. There's quite a bit of machinery in there (ConfigureAwait) to control whether your async routine is run on the UI thread or on a different worker pool thread.In a Unity context, the engine provides the main loop and the developer is writing behaviors for game entities.
twoodfin: As the author lays out, the thing that made coroutines click for me was the isomorphism with state machine-driven control flow.That’s similar to most of what makes C++ tick: There’s no deep magic, it’s “just” type-checked syntactic sugar for code patterns you could already implement in C.(Occurs to me that the exceptions to this … like exceptions, overloads, and context-dependent lookup … are where C++ has struggled to manage its own complexity.)