OCaml 5; domains, Erlang, Beam, OTP

The other thing Erlang’s design does by choice AFAIK, is that it emphasizes the runtime very strongly. The language is interpreted by design, with every single instruction being measurable. Every Erlang program is first and foremost a distributed runtime assuring minimal latency and fault tolerance, and an actual program concerned with performance second.

There is a lot to unpack, but essentially async exceptions appear hopeless if one only has a defensive exception-safety model in mind (that asks the programmer to have in mind every location in the code where an exception might arise). The literature has focused on features to manage asynchronous exceptions—e.g. Haskell bracket combinator—without providing evidence that the features suffice (they do not) and without locating them within a reasoning model.

Less academic sources, on the other hand, contain valuable insights on how to program with asynchronous exceptions. These insights can be found in some Haskell blogs and in programming guidelines for the Isabelle and Coq proof assistants. The reasoning principles that explain those hard-learned lessons eventually come from the literature on exception-safety (e.g. C++) and fault-tolerance (e.g. Erlang’s let-it-crash). Interestingly, the C++ exception-safety principles were tested in Abrahams’ original paper by having every function call randomly raise an exception, e.g. as if there were asynchronous exceptions in C++.

I was saying that this is important also for people who do not care about having asynchronous exceptions per se. It happens to be the same exception-safety model that lets you interrupt your programs and be fault-tolerant (i.e. rationalizing the process of catching uncaught exceptions at top-level and then exiting gracefully or restarting, and generalizing this model to Erlang-style monitors).

The discussion I linked on cancellation with lightweight threads is another example. The thread goes in several directions but one take-away for me is that cancellation/interruption: 1) becomes even more useful in concurrent and parallel settings, and 2) dealing with it looks a lot like dealing with asynchronous exceptions. The place where the polling happens changes (e.g. now when performing effects), but since you still want to poll often enough, you have to have enough of them that any defensive exception-safety model will impose strong structural constraints on your programs before you even start taking into account any domain-specific requirements, and without guarantee that this still resembles functional programming. Then it is useful to still think about them as asynchronous exceptions. The same argument can be given about the suggestion I sometimes heard that it would be possible do without asynchronous exceptions from OCaml as one just needs to poll by hand often-enough.

Lastly, you are also asking whether fibers are pre-emptive. Fibers can be interrupted asynchronously (e.g. when reaching a time or space limit), but they cannot yield asynchronously for implementation reasons. There exist such notions as “asynchronous effects” that could model pre-emptive fibers, but it looks like some work (purely from an engineering perspective) to make it such that it becomes possible in OCaml to perform effects from inside asynchronous callbacks (but it does not look impossible). This is different from system threads, which are already preemptive, as other people have mentioned, but are not as lightweight.

1 Like

But Eio doesn’t have only a defensive exception-safety model. It has a structured concurrency model–child fibers are owned by parent fibers. If a child fiber raises an exception, the parent fiber will know about it: Fiber (eio.Eio.Fiber)

The new fiber inherits sw 's cancellation context. If the fiber raises an exception, Switch.fail sw is called.

I place Eio’s cancellation model among the non-defensive ones, hence why I linked to the discussion.

You might also find ZIO’s (Scala) similar model interesting: Introduction to ZIO Fibers | ZIO

They are more production-ready because of various factors, and also set to take advantage of Java’s new green threads.