| I'll take a stab at elaborating. The essay is about callback-based APIs, so types and encapsulation are out of scope from the start. It then expands the scope and observes that OO principles don't address the points covered. For example, it says that one of the "magic" requirements would be a way to state: "Do not add a callback that calls log() or acquires any locks held while log() is called." There is no type for that. Other than pure functional code, there's no way to do that. The essential equivalent for a multi-actor system is deadlock prevention. OO principles don't help there either. You can get the problem with a stream. Consider a logger stream, where the listener opens a database connection to save the value then closes it, and the database adds 'open' and 'close' events to the logger stream. This will lead to an geometric explosion of events on the stream, because nothing at the API level says you shouldn't put those pieces together that way, other than the documentation. I could go into the OO details of how this stream might be implemented in Dart, but really the OO nature of the stream API obscures the essential self-referential nature of the problem. You can propose an equivalent counter-example if you want to demonstrate that those APIs really do solve the problem. I happen to agree with the well-written essay, and OO principles or "proper async APIs" solve nothing. |
We do some crazy async HPC code, and during on-boarding, new members invariably get some initialization / error handling wrong with raw callbacks, and convert pretty quick to FRP after that. Unstructured async is crazy.