Add ApplicativeError#voidError - #4324
Conversation
| /** | ||
| * Void any error, by mapping it to `Unit`. | ||
| * | ||
| * @see [[handleError]] to map to an `A` value instead of `Unit`. | ||
| */ | ||
| def voidError[A](fa: F[A]): F[Unit] = handleError(void(fa))(_ => ()) |
There was a problem hiding this comment.
Alternatively this could be def voidError(fu: F[Unit]): F[Unit] which may be used like fa.void.voidError. For some reason I thought that was awkward, but looking at it again it seems reasonable.
There was a problem hiding this comment.
Also I guess I should use Function.const here.
There was a problem hiding this comment.
I kind of like taking F[Unit] since if we have to call void on it then when A = Unit we are doing wasteful work.
It's a kind of false generalization. We can only accept any A by voiding so why not have the caller void.
johnynek
left a comment
There was a problem hiding this comment.
Seems useful but maybe we could expand the comment about the motivation (since ignoring errors is often an anti-pattern).
Co-authored-by: Daniel Spiewak <djspiewak@gmail.com>
| * This is useful when errors are reported via a side-channel but not directly handled. | ||
| * For example in Cats Effect: | ||
| * | ||
| * {{{ | ||
| * IO.deferred[OutcomeIO[A]].flatMap { oc => | ||
| * ioa.guaranteeCase(oc.complete(_).void).void.voidError.start | ||
| * // ... | ||
| * } | ||
| * }}} | ||
| * | ||
| * Without the `.voidError`, the Cats Effect runtime would consider an error in `ioa` to be | ||
| * unhandled and elevate it to [[scala.concurrent.ExecutionContext.reportFailure ExecutionContext#reportFailure]]. |
| def laws: ApplicativeLaws[F] | ||
|
|
||
| private def makeEqFUnit[A](a: A)(implicit EqFA: Eq[F[A]]): Eq[F[Unit]] = | ||
| protected[discipline] def makeEqFUnit[A](a: A)(implicit EqFA: Eq[F[A]]): Eq[F[Unit]] = |
There was a problem hiding this comment.
So by changing it from private to protected[discipline] you're making it accessible not only for sub-classes but also for everyone in discipline – is that correct?
There was a problem hiding this comment.
Oh, hm. Maybe that should be private[discipline]. The goal is to have it available for us, but not public.
There was a problem hiding this comment.
| protected[discipline] def makeEqFUnit[A](a: A)(implicit EqFA: Eq[F[A]]): Eq[F[Unit]] = | |
| private[discipline] def makeEqFUnit[A](a: A)(implicit EqFA: Eq[F[A]]): Eq[F[Unit]] = |
There was a problem hiding this comment.
Although I have no objections in regards to the PR, but I'm sort of curious about the initial implementation there:
def makeEqFUnit[A](a: A)(implicit EqFA: Eq[F[A]]): Eq[F[Unit]] =
Eq.by(fa => laws.F.as(fa, a))
What could be a rationale of making Eq[F[Unit]] from an arbitrary a: A value?
Perhaps, I'm missing something, but it seems like for two different a it will produce two F[Unit] (even for the same F type) that would be considered as unequal to each other. Is that correct?
There was a problem hiding this comment.
What could be a rationale of making
Eq[F[Unit]]from an arbitrarya: Avalue?
We would normally request an Eq[F[Unit]] as an implicit parameter, but we cannot do so without breaking binary-compatibility.
Perhaps, I'm missing something, but it seems like for two different
ait will produce twoF[Unit](even for the sameFtype) that would be considered as unequal to each other. Is that correct?
That is correct, this is just a workaround when you have a constant a.
Fixes typelevel/cats-effect#3152.