Hacker News new | ask | show | jobs
by jayd16 1465 days ago
Yeah, it's a nice way to kludge in yielding/cooperative execution without bringing in the threading syntax of async/await.

It's still a bit of a miss match though. Delay instructions and waiting for other coroutines are implemented as type unsafe yield return values. Still, a pretty good hack. It ends up with a lot less garbage than async/await.

2 comments

Not really. Tasks can be zero garbage, IEnumerable cannot. A 'task' in C# is just something that has a GetAwaiter() method, which gives you a callback on when something has happened.

This is how ValueTask is implemented in newer .NET versions which is a struct, but you can roll your own.

Yes really. It's huge effort to make this happen. ValueTasks bring their own gotchas, like not being able to be awaited multiple times. Yielding from an existing IEnumerator is free while every await is a chance to cause garbage with a new awaitable. Even Task.Yield() allocates garbage (in Unity at least) and trying to get Unity lifecycle events as cheap and safe awaitables is not really feasible. At least at the moment.
> Delay instructions and waiting for other coroutines are implemented as type unsafe yield return values

Can you elaborate? I was under the impression that `YieldInstruction` is a well-defined type.

You would use the base IEnumerator that yields object types. `YieldInstruction`s are a type that the Unity coroutine runtime will recognize but you can yield anything. Some have meaning like YieldInstruction, Coroutine, CustomYieldInstruction and others that Unity will recognize as some special command to wait before the next iteration. As far as I know there is no exhaustive public list. You can also just yield anything else from int to stream.

Yielding a final value that isn't a yield instruction is a technique to return a value from a coroutine. You can pull the final return value from the IEnumerator's Current property. Hacks on hacks but it gets the job done.