3 ms·
From a mathematical perspective, synchronous code is strictly more powerful and say-what-i-mean. Asynchronous code is closer to how a (modern) computing system
by buzzybee 10y ago
From a mathematical perspective, synchronous code is strictly more powerful and say-what-i-mean. Asynchronous code is closer to how a (modern) computing system functions in practice.
And yes, a large percentage of our use-cases for callbacks tend to be of the "yield execution of a multi-step task" form. But it isn't just callbacks, it's anything of a "concurrent-and-branching" type flow, so game AIs, UI, etc. also run into this stuff a lot. Sometimes it can be dealt with informally, other times it needs more structure for engineering with confidence to be possible.
A formalized finite state machine is one solution to making sense of the problem in a more generalized way: instead of handing off execution flow based on a morass of polling and callbacks, there's a big switch statement to represent the FSM. The end of each branch of the FSM dictates what the next branch is by setting a branching variable. And every branch ultimately calls into the FSM again, either via a callback or an external loop. This style has the upside of an easier debug trace and the downside of another variable to track and potentially mishandle. (overall, a net gain as the FSM scales up)
A more composable form of FSM used in game AI is the "behavior tree", which encodes blocks of logic in each node of the tree, each node returning a status code: success, failure, in-progress, and optionally taking an action affecting external state like "play animation" or "fire weapon". The general progression is a walk from roots to leaves, with some nodes used to determine the exact sequencing(left to right, pick random, etc.) and other nodes used to tell the tree to yield execution or restart processing by sending back a status code. With behavior trees, there's a substantial win for reusability since the nodes cleanly delineate their needs for parameters, allocation, yielding, etc.
At the language level we're still mostly catching up on strategies that give the idioms comfortable syntax. Yielding iterators (such as those in Python) and promises can sometimes substitute for the simple case of calling a sequence. Full-blown continuations exist in several languages and are very powerful but also encode too much program scope to be used at scale or for long-running, persistent tasks.