My reading of the effects paper is that in addition to improving on the programmability, that the effects should be strictly equal to or higher performance than the equivalent monadic code (modulo things like flambda). With the primary reason being that it can avoid allocating closures etc.
My use case is a state machine for a distributed system where on each iteration it receives a list of incoming messages and emits a list of messages to send.
In the benchmark I am testing just the emitting of the messages to send by looping to send all the βmessagesβ (integers here from n β 0). There is also a (minimal?) variation which does the same using a reference.
I suspect that what is happening is a tradeoff between unrolling the stack (for the effect system) and the allocations for the monad, but it is also highly likely that I have missed something obvious!
(also just to point out that the effects system not being quite as fast as for example the monadic approach means nothing when you consider that you get a very very good way of writing generic effectful code without having to deal with coloured functions).
With effects I think you only need to pay the βcostβ of the effect when the effect is actually triggered (e.g. on a syscall, although I assume for network syscalls you could also perform them optimistically and rely on EAGAIN to trigger the effect, but I havenβt checked how EIO is implemented).
With monads you have to pay that cost all the time, because each computation and function return type needs to be wrapped in the monad, which can result in the allocation of a lot of closures, especially when a value is waiting on the return of a syscall (some more short-lived than other, although Lwt has some optimizations here when the result is immediately known I think it can still build up chains of deferred values when the Lwt.t result is not immediately available).
So a more realistic comparisons of concurrency monads vs effects would be to measure both paths:
immediate value propagation where the monad, or the compiler via flambda can optimize away some of the overhead
suspended/blocked values, which might trigger the construction of a lot of closures to be run when the value is available (probably best to measure the Lwt and Async implementation here directly, because theyβll be a lot more complicated than simple ones, especially that they might also have to deal with cancelation, etc. and they may also have some optimizations,
e.g. I think Lwt uses mutation internally to avoid some pathological cases
). This depends on the depth of the call-stack (so e.g. try 10-30 binds after the βsleepingβ monad value), but also if you happen to fold_left bind on a list the chains can be much much longer.
I think effects can avoid the latter problem altogether, and see Reflection without Remorse for a description of the problem (it affects Haskell more because it doesnβt have mutation, and has to resort to other data structures to recover the performance cost with long monad chains, I think Lwt achieves a similar optimization through the use of mutation, but a naively implemented monad would have the performance cost)
Sorry if this seems out of place, but whatβs this Caml.Effect module you open? I donβt see it in the standard library nor find any reference to it on the web.
Oh sorry, I keep forgetting that 5.0 isnβt the official release yet. (Iβm still on 4.13.1 but I have my eye on 5.x for Eio & friends. Didnβt think effects would be in that release; I thought they were for much later. I must be confusing βeffectsβ vs βtyped effectsβ.)
Indeed, there hasnβt been much (visibly) going on for effect typing in the compiler, but the runtime mechanism for effect handlers (delimited control support, new garbage collector, etcβ¦) has been in the works for the last few years and has successfully landed on 5.0.0
That post is quite old and focuses on user-level delimited continuations from the honestly excellent delimcc library. Effectsβ delimited continuations are first-class in the runtime and limited to linear mode of usageβ¦ I imagine that gives them different perf characteristics?
There was a blog post where the authors of angstrom observed perf improvements when they switched from lwt to effects, let me see if I can find itβ¦