-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Weaken some Alternative
constraints in OneAnd
#4739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@@ -123,8 +123,21 @@ final case class OneAnd[F[_], A](head: A, tail: F[A]) { | |||
s"OneAnd(${A.show(head)}, ${FA.show(tail)})" | |||
} | |||
|
|||
private[data] trait OneAndBinCompat0[F[_], A] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[question] Is this the right way to pass the MiMa check for a case class
modification?
I saw #3997 (comment) and thought that this was the (only) way, but I could not find any other place that defines a similar bincompat trait
(other than ValidatedFunctionsBinCompat0
, which patches the companion rather than the Validated
class itself).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we make this sealed? I think so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I made it sealed
: af23366
val head: A | ||
val tail: F[A] | ||
|
||
@deprecated("Kept for binary compatibility", "2.14.0") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[question] Is since = "2.14.0"
specification appropriate (is that the next cats version)? Or do I just not need @deprecated
at all since it's private[data]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
personally I wouldn't add the deprecated and just add a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a method is superceded by some other method with the same name, we usually not only make it package local, but also remove all implicit
keywords from its definition, e.g.:
private[data] def combine(other: OneAnd[F, A])(F: Alternative[F]): OneAnd[F, A] = ...
which makes it less likely to interfere with the new method while preserving binary compatibility.
I personally don't mind marking it @deprecated
but don't have strong opinion on that – it is not supposed to be called anyway.
Oh, I thought I made the bincompat check pass but I didn't! I'll try to fix it. |
the situation looks very similar to https://github.com/typelevel/cats/pull/4055/files#r760450709.
val head: A | ||
val tail: F[A] | ||
|
||
@deprecated("Kept for binary compatibility", "2.14.0") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
personally I wouldn't add the deprecated and just add a comment.
@@ -123,8 +123,21 @@ final case class OneAnd[F[_], A](head: A, tail: F[A]) { | |||
s"OneAnd(${A.show(head)}, ${FA.show(tail)})" | |||
} | |||
|
|||
private[data] trait OneAndBinCompat0[F[_], A] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we make this sealed? I think so.
val head: A | ||
val tail: F[A] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Abstract vals look suspicious a bit. And might not be necessary – since OneAndBinCompat0
is supposed to be extended by OneAnd
only, a trick with self-type annotation might work here:
private[data] trait OneAndBinCompat0[F[_], A] {
self: OneAnd[F, A] => // allow access to `head` and `tail` from withing this trait
// no abstract `head` and `tail` should be necessary
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason I've never used a non-trait
type for self-type annotation and couldn't come up with this!
Applied: af23366
private[data] def unwrap(implicit F: Alternative[F]): F[A] = | ||
F.prependK(head, tail) | ||
|
||
// Kept for binary compatibility | ||
private[data] def combine(other: OneAnd[F, A])(implicit F: Alternative[F]): OneAnd[F, A] = | ||
OneAnd(head, F.combineK(tail, other.unwrap)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While not a requirement, but since there's self: OneAnd
in the scope and because Alternative
extends NonEmptyAlternative
, I wonder if it could be simplified even further:
private[data] def unwrap(implicit F: Alternative[F]): F[A] = | |
F.prependK(head, tail) | |
// Kept for binary compatibility | |
private[data] def combine(other: OneAnd[F, A])(implicit F: Alternative[F]): OneAnd[F, A] = | |
OneAnd(head, F.combineK(tail, other.unwrap)) | |
private[data] def unwrap(implicit F: Alternative[F]): F[A] = | |
self.unwrap(F) | |
// Kept for binary compatibility | |
private[data] def combine(other: OneAnd[F, A])(F: Alternative[F]): OneAnd[F, A] = | |
self.combine(other)(F) |
Also, I would still recommend to go without implicit
parameters here because even though these methods are private[data]
they are still visible to Cats' internals and may cause unexpected unexpecties in the future. Not a requirement either, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense. I think the same applies to OneAndInstancesBinCompat0
as well, so I made a similar change to the instances trait too (e059ed8).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
Currently, the
unwrap
andcombine
methods inOneAnd
, as well asSemigroupK
/Semigroup
instance haveAlternative
as a bound for the typeF[_]
of collection-like component.This pull request weakens this constraint to
F[_]: NonEmptyAlternative
.Context
The change allows one to
unwrap
OneOf[NonEmptyList, A]
intoNonEmptyList[A]
. At first glance puttingNonEmptyList
inOneOf
sounds a bit weird, but I think they are natural choices for situations when one wants to describe a collection of2..N
items (this occurred to me while describing "duplicate inputs error" in a validation logic, where the errorcase class
had a length ≥2 list of input indices containing duplicates).I think this
weakeninggeneralization makes sense since, intuitively, none of the aforementioned methods interact with theempty: F[Nothing]
aspect of the collection: they only combine collections (SemigroupK
) or inject an element into the collection (NonEmptyAlternative
).