The Scala community has done a lot of nice work on capability-passing designs, and over time they grew some language support to make it nicer.
My impression (from afar) is that the Scala community is deeply divided between:
- people who use Scala like a JVM-based ML (impure, code that looks like a mix of java and ML, etc.). That includes Martin Odersky.
- people who try to rebuild Haskell on top of Scala (ZIO, cats, etc.).
I imagine the people playing with capabilities belong in the second group, not the first one. Also, they have language support we don’t: implicits for Scala 2, typeclasses for Scala 3. OCaml is a lot more explicit in general.
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
In general, trying to solve fragmentation with 5 libraries doesn’t involve building a 6th one that has an even wider scope. As mentioned earlier in this thread, Eio seems very big and monolithic.
What I would hope for, personally, is a small, carefully chosen set of effects (not handlers) that spell the grammar for non blocking IO and lightweight concurrency. This way I can remove the functor (Io : IO) -> …
in some of my code and use these instead. Then everyone is free to implement these handlers in their own event loop. This is like having Seq
in the stdlib, and everybody building on that.
but I haven’t seen proposals in this thread that sound like better answers.
What about building on top of Lwt?
Could we see a concrete example of how “costly” the passing-around-stuff explicitly idioms become when relying on EIO
Imagine using directories
or xdg
to store some local data, and having to carry that from your main
down to the deepest function that wants to use a cache. openat
has its use, but don’t just deprecate open
Unrelatedly:
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.
I think Haskell sends the second thread into a “black hole”? On Lazy.force foo
you could swap the thunk inside foo
with one that suspends-and-yields. Maybe the problem is that domains don’t always come with a scheduler that provides the “yield” primitive, or maybe it just parks the current Thread.t
.