Is it possible to make the object capability style optional, e.g. part of an eio.cap
library built on top of a core eio library? (they could still both live in the same repository to make things easier)
Then users who like/want to use capability style could use eio.cap
which doesn’t expose any direct access and you need to provide a capability to each function, and those who don’t could use the slightly lower level eio
?
I appreciate that Eio with capabilities may encourage a certain style of writing your programs which may be less error-prone, or at least force you to think about what your functions really need access to, but if you’re trying to integrate this with existing code sooner or later you might find that you need some escape hatches for compatibility and at that point it’ll be difficult to prove that your program is still safe.
However that should be implementable on top of a thin abstraction layer that just wraps Unix / uring / etc., and make it easier to gradually adopt multicore into a project.
E.g. when I attempted to implement a module to protect against file descriptor leaks I ended up having to implement something similar to Rust’s move semantics - with runtime checks - because otherwise the file descriptors could simply not be used for common things like caches or resource pools where the file descriptor would outlive its caller. I’m not happy with the resulting API (xen-api-libs-transitional/resources/unixfd.mli at master · xapi-project/xen-api-libs-transitional · GitHub and xen-api-libs-transitional/resources/safe.mli at master · xapi-project/xen-api-libs-transitional · GitHub), it is only safe as long as you follow a certain convention of not storing/using more than once the result of ‘dereferencing’ a safe file descriptor, and is cumbersome to use. And the first time someone else wrote a PR to that piece of code they promptly used the escape hatches in the API to bypass the safety checks, because writing it the correct way was entirely non-obvious and difficult to figure out.
I’d love to explore how to implement such an API on top of EIO, but that’d also require move semantics (I think) to make it practical. However I wouldn’t want to make that pervasively part of the EIO API.
Some of the tension in the API design might come from trying to use OCaml’s type system to prove all sorts of safety properties for our programs, and although the type system is great for proving some properties, perhaps more complicated properties like linearity or capabilities would better be left to static analyzers, and all an API should provide are annotations to be processed by a static analyzer?