I’m working on a comparison between capabilities and algebraic effects. Given that we don’t have much documentation on what capabilities are yet, I’m reaching out to try to clarify some aspects:
1. What are capabilities? It seems Caprese is introducing two different effect trackings: capture tracking (^{...}
) and context functions (?=>
). Can we say context functions is what is meant as capabilities and capture tracking is a separate solution to make them safe by avoiding escaping? How do these three concepts (capture checking, context functions, and capabilities) relate to each other in Caprese’s design?
2. Do capabilities offer features beyond implicits? I’ve noticed that context functions desugaring generates good bytecode but, other than that, do context functions/capabilities offer any features beyond what can be achieved with regular implicits?
3. How do you combine capabilities? Given that context functions take a single input and that a computation can typically use multiple effects, what’s the recommended way to express an API that requires multiple capabilities? For instance, if a function needs both Async
and Database
capabilities, is the idiomatic approach (using Async, Database)
or is there a composition mechanism like Async & Database
? When falling back to regular implicit declaration, is that also considered capabilities?
4. Is there capability inference? Given the nature of implicits/context functions, it seems users will have to manually declare capabilities in method signatures and can’t rely on the compiler’s inference / auto complete to fill them. Is this understanding correct?
5. Will capabilities offer first-class continuations? If I understand correctly, the explorations so far rely on runtime-provided thread blocking, which can be virtual now with Loom. Are there plans to offer more proper support for continuations? How about multi-shot continuations?
6. Are side effecting capabilities purely functional? I’ve been noticing effect tracking via capabilities being mentioned as purely functional. For example, def setState[A](s: A)(using State): Unit = this.state = s
requires a State
capability but executes a regular side effect immediately. Can that be considered purely functional? If so, what distinguishes this from traditional imperative programming with parameter passing?
7. How do capabilities avoid unsafe compositions? Some capabilities shouldn’t be used in specific contexts. For instance, a State
capability being used within parallel computations could lead to inconsistent state. How does Caprese prevent or signal such unsafe usage? If I have a State
capability and attempt to use it within Future.traverse
or similar parallel constructs, what happens? Is there a way to express that certain capabilities should not be used in specific contexts, or is this left to user discipline?
Thank you in advance,
Flavio