Live data from Hacker News

Looking at Unity made me understand the point of C++ coroutines

mropert.github.io

21–30 of 190 posts

Re: Looking at Unity made me understand the point of C++ coroutines

#21

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…

Hmm. I'm fairly certain that most of that assembly code for saving/restoring registers can be replaced with setjmp/longjmp, and only control transfer itself would require actual assembly. But maybe not. That's the problem with register machines, I guess. Interestingly enough, BCPL, its main implementation being a p-code interpreter of sorts, has pretty trivially supported coroutines in its "standard" library since th…

setjmp + longjump + sigaltstack is indeed the old trick.

Re: Looking at Unity made me understand the point of C++ coroutines

#22
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.)

Re: Looking at Unity made me understand the point of C++ coroutines

#23
post #5

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.

IIRC generators and co-routines are equivalent in a sense that you can implement one with the other.

Re: Looking at Unity made me understand the point of C++ coroutines

#24
post #8

Earlier quoted context omitted.

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. Edit: Nevermind, they eventually bothered.

Unity has async too [1]. It's just that in a rare display of sanity they chose to not deprecate the IEnumerator stuff. [1] https://docs.unity3d.com/6000.3/Documentation/ScriptReferenc...

Oh I totally missed this, thanks! I was overly confident they wouldn't have bothered, given how long it was taking. The last time I used Unity was 2022.3, which was apparently the last version without Awaitable.

Re: Looking at Unity made me understand the point of C++ coroutines

#25
post #5

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.

>The use of IEnumerable as a "generator" mechanic is quite a good hack though.

Is that a hack? Is that not just exactly what IEnumerable and IEnumerator were built to do?

Re: Looking at Unity made me understand the point of C++ coroutines

#26

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 struggle…

If you need to implement an async state machine, couldn't that just as easily be done with std::future? How do coroutines make this cleaner/better?

Re: Looking at Unity made me understand the point of C++ coroutines

#27

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…

Hmm. I'm fairly certain that most of that assembly code for saving/restoring registers can be replaced with setjmp/longjmp, and only control transfer itself would require actual assembly. But maybe not. That's the problem with register machines, I guess. Interestingly enough, BCPL, its main implementation being a p-code interpreter of sorts, has pretty trivially supported coroutines in its "standard" library since th…

You can do a lot of horrible things with setjmp and friends. I actually implemented some exception throw/catch macros using them (which did work) for a compiler that didn't support real C++ exceptions. Thank god we never used them in production code.

This would be about 32 years ago - I don't like thinking about that ...

Re: Looking at Unity made me understand the point of C++ coroutines

#28
post #5

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.

Thankfully they are actively working towards upgrading, Unity 6.8 (they're currently on 6.4) is supposed to move fully towards CoreCLR, and removing Mono. We'll then finally be able to move to C# 14 (from C# 9, which came out in 2020), as well as use newer .NET functionality.

https://discussions.unity.com/t/coreclr-scripting-and-ecs-st...

Re: Looking at Unity made me understand the point of C++ coroutines

#30

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 struggle…

If you need to implement an async state machine, couldn't that just as easily be done with std::future? How do coroutines make this cleaner/better?

std::future doesn't give you a state machine. You get the building blocks you have to assemble into one manually. Coroutines give you the same building blocks but let the compiler do the assembly, making the suspension points visible in the source while hiding the mechanical boilerplate.

This is why coroutine-based frameworks (e.g., C++20 coroutines with cppcoro) have largely superseded future-chaining for async state machine work — the generated code is often equivalent, but the source code is dramatically cleaner and closer to the synchronous equivalent.

(me: ex-Visual Studio dev who worked extensively on our C++ coroutine implementation)

Post reply on HN