Open fwbrasil opened 4 weeks ago
I believe the ZIO model for errors is brilliant and kyo would greatly benefit from it:
Btw, have you @fwbrasil considered constraining Result
errors only to Exception
? Like
opaque type Result[+E <: Exception, +A] >: (Success[A] | Failure[E]) = Success[A] | Failure[E]
E
stands for those typed, recoverable/expected errors, right, but in my experience they should still always be subclasses of Exception
for good interoperability with the JVM and ecosystem around it.
Btw, have you @fwbrasil considered constraining Result errors only to Exception?
I think @hearnadam also suggested that some time ago. The intent was make Result
have the features of both Either
and Try
and allow Abort
for any value like in ZIO. I haven't seen much benefit in the approach yet, though. There's only the swap
method that might not make sense if we add this restriction. @johnhungerford can you share you thoughts? I added swap
inspired in the equivalent combinator method.
I believe the ZIO model for errors is brilliant and kyo would greatly benefit from it:
- typed channel for recoverable/expected errors
- untyped channel for unrecoverable/unexpected failures
I think that's what have already given that Result
and Abort
handle both typed (Result.fail) and untyped failures (Result.panic).
I definitely would not want to restrict errors to Exception
in kyo
. For instance, we should be able to use Abort
as an Option
-like effect by aborting with Maybe.Empty
(or whatever it's called), which is not an exception.
I don't find Abort[Maybe.Empty]
very useful. In most cases, I prefer returning a regular Maybe
so the caller has to handle the effect immediately and, in cases like a missing config, a specific exception seems better since it can communicate the cause of the abort more clearly. @johnhungerford do you mind sharing more on why you feel that's a useful pattern? To be honest, I'm still struggling to see the value of tracking Abort[Throwable]
as well since it's essentially what the always-present Panic
is 🙃
A < (S & Abort[Maybe.Empty])
is equivalent to OptionT[S, A]
: it combines the Option
monad with other effects. I find this very useful in any case where I need to abstract over the composition of optional values while also abstracting over other effects. For instance, say you are writing a function to generate a result from multiple functions that return optional values asynchronously. In this case, you may want to lift those values to < Abort[Maybe.Empty]
and let any empty value short-circuit the logic.
I agree in this case you probably want to then convert the A < (Abort[Maybe.Empty] & Async)
back to an Option[A] < Async
at the end of your function, but you still need to use Abort
within the function. I also agree than in more cases you will want to preserve some information along with the missing value, but I have definitely encountered plenty of situations where I'm dealing with straightforwardly optional values. I've used this pattern plenty in ZIO
.
That seems like an abuse of Abort
, whose purpose is to track typed, recoverable/expected errors. It's not that I'm morally condemning writing code like that, it will "work", but maybe it is a symptom of a lack of an OptionT
-like effect in Kyo?
Obviously you have to do it like that in ZIO, because that's just how ZIO is, you don't have much choise. But isn't the point of Kyo to be more flexible, making it easy to add such an effect, which would be analogous to OptionT
?
If Abort
were simply for errors, it would be called Error
. Abort
is for "aborting," or short-circuiting a computation. Why would it matter whether this is for errors or empty values? There used to be a separate Option
effect in Kyo, but it was removed, since was basically just an alias for Abort[None]
.
A < Abort[B]
, represents a computation that may complete with a value of type A
or abort with a value of type B
. This way of thinking about aborts is consistent with both errors and options.
Again, in most cases I would probably handle A < Abort[Maybe.Empty]
to Maybe[A] < Any
at the end of a function, but I think it makes perfect sense to use Abort
to abstract over short-circuiting missing values.
To be honest, I'm still struggling to see the value of tracking Abort[Throwable] as well since it's essentially what the always-present Panic is 🙃
For me the same is true about Abort[Nothing]
which you get if you just use Abort.panic
with no other failure. In https://github.com/getkyo/kyo/pull/690/files I had incorrectly assumed could safely be eliminated and would be handled by the kernel. Abort[Nothing]
is especially problematic because you cannot derive a ClassTag[Nothing]
(or a Tag[Nothing]
but that could be solved although that might introduce other problems). I think it is worth considering what panic only looks like going forward (if it should even exist).
If
Abort
were simply for errors, it would be calledError
.
Fair enough. @fwbrasil do you think kyo would benefit from an effect dedicated purely to typed recoverable/expected errors?
Review Abort, Result, and related kyo-combinators methods to follow a naming pattern similar to ZIO's since it's quite mature and it would be helpful to people coming from ZIO. We should also review whether the APIs provide similar semantics to ZIO. Context: https://github.com/getkyo/kyo/pull/644#discussion_r1749345497