In 1968 Dijkstra sent the memo “GOTO considered harmful”. Something similar is happening now with asynchronous callbacks.
One way of evaluating if a control construct is good is to evaluate: does the flow go from the top to the bottom? Goto violates this 1. Functions are thought of as black boxes. But goto allows you to jump out of it somewhere else (in some languages - not in C).
Modern network programming is however full of something similar to goto: asynchronous callbacks. It basically allows you to jump out of a function, because the asynchronous callback is called after the function that sets it up finishes. To make this obvious, just add print statements in the code that indicate when each bit is executed and you’ll see it jumps around everywhere - definitely not from top to bottom.
A similar situation exists with state machines. Looking at it top-to-bottom does not say anything about the actual execution flow.
Go coroutines at first sight seem to be a solution, because the coroutine itself looks nicely top-to-bottom. However, the actual execution flow is no longer visible, because in the background the coroutine is still running while you’re doing other stuff.
There are some libraries that improve this, by making a scope for the coroutines so at least it is easy to see where they end: libdill for Go, trio for Python. They differ in how they close the scope: libdill cancels everything, trio waits for everything to finish (except if an exception is thrown).
Open problems are how to handle e.g. timeouts, grace period (i.e. some time before cancellation is forced).
if used incorrectly… ↩