With my compiler hat on, some things I’m mildly worried about is as follows:
- Currently the Multicore-enabled compiler only provides low-level primitives for parallelism, and basically nothing for concurrency. (In fact, we do have the
Threads
module that works surprisingly well with Multicore. It was built for backwards-compatibility only but currently it’s, ironically, a fairly sensible option to write concurrent code in Multicore.) - The idea from the start was to be able to write concurrency support (an event loop, etc.) in user land on top of fibers / effect handlers, to experiment with what works best for various problem domains, etc.
- But then, if everyone does something different, there is a risk of fragmentation of the ecosystem where we end up with 5 different concurrency abstractions that can’t talk to each other, and OCaml beginners have to choose the camp they belong to from day 1. (That wouldn’t happen, right? We totally didn’t do that for cooperative concurrency libraries, build systems, package managers, etc.) Exploring many different approaches is great, but ending up with insular ecosystems is not great.
I think that the EIO people are hoping that their honest effort to come up with a good concurrency story on top of the low-level compiler primitives will win everyone’s heart, people will adapt existing libraries (Lwt, Async, what have you) on top of it or move to their new code, no fragmentation anymore, end of story. And given that there are steady contributions to EIO, with excellent people like @talex5 working on this, coming from highly-respected OCaml shops that have a lot of influence in the ecosystem, for tooling decisions, etc., this sounds like a plausible scenario!
If people are worried that EIO “is not Foundational enough” (as in: we’d like to do something different that is not on top of EIO, but on top of the low-level primitives), do they have plausible proposals for how to avoid ecosystem fragmentation? For example, we could consider some of the following ideas:
-
Hope that the various concurrency libraries will be able to collaborate with each other (integrate their event loops together somehow?). That sounds very hard, and to my knowledge we already didn’t manage to do this in the sequential world – but then people like @antron know much better than I do about this.
-
Design a sort of mid-level concurrency layer that is more high-level than just domains, and expressive and non-opinionated enough that people want to build on top of that, and cooperate through that mid-layer. But what would this be? Isn’t the “concurrency primitives” part of EIO something like that?
-
Your suggestion here.
In theory, we are not in a real hurry to solve this question: OCaml 5.00 is not out yet, it will not be a production-ready release that all projects jump onto from day 1, we can expect a stream of increasingly robust 5.x releases with only some parts of the ecosystem getting their foot wet at first. And it’s not reasonable to expect people to come up with full answers to questions about how to use an implementation that is not released yet! (Note: the Multicore people have a head-start here thanks to their experiments on top of the Multicore runtime; everyone could have participated, but few people had the time (and funding) to do this, it’s great that they did many experiments.)
In practice, there are some basic questions about OCaml programming that are hard to answer right now about OCaml 5.0, because we don’t know what to recommend to users willing to write multicore code. For example, Lazy
values cannot be used concurrently, and the reason why is that we don’t know how to block code that forces a thunk that is already being forced by someone else. (We could do this with a domain mutex, but this would block the whole domain, whereas people want something that will only block the “current fibre” and yield to another concurrent computation on the same domain.) This is one example of the Stdlib, but I’m sure there will be many other examples once people start porting their projects to Multicore: whenever the natural answer to a question is “well you should block until X happens”, nobody knows what’s the good way to do this, because we don’t know what concurrency layer the user wants to use – we don’t know what blocking means for our end-users.
So I think that we urgently need some sort of standard for these questions. I don’t know if EIO is the right answer, but I haven’t seen proposals in this thread that sound like better answers. (Of course people were discussing different things, like “what’s the best way to adapt full programs to Multicore”.) My intuition is that if we think hard enough about this, we may find reasonably simple answers that can please everyone, because “how should library block on an operation” sounds like an easier question than “what’s a good API design for all interactions with the OS?”. Well…