-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Sync NEL and NEV methods (fixes #1832) #1838
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1838 +/- ##
=========================================
+ Coverage 96.09% 96.1% +0.01%
=========================================
Files 273 273
Lines 4554 4566 +12
Branches 129 122 -7
=========================================
+ Hits 4376 4388 +12
Misses 178 178
Continue to review full report at Codecov.
|
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 for sending the PR to fix this!
/** | ||
* Append another NonEmptyList | ||
*/ | ||
def concatNel[AA >: A](other: NonEmptyList[AA]): NonEmptyList[AA] = |
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.
why can't this just be concat
? NonEmptyList
and List
are different types. I'm not sure why we took this route and if there is not a good reason I'd rather change it before 1.0.
@@ -139,12 +153,6 @@ final case class NonEmptyList[+A](head: A, tail: List[A]) { | |||
} | |||
|
|||
/** | |||
* Append another NonEmptyList | |||
*/ | |||
def concat[AA >: A](other: NonEmptyList[AA]): NonEmptyList[AA] = |
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.
I like this naming better. We should add concat
to NonEmptyVector in my opinion, not remove here.
@johnynek I guess the |
def reverse: NonEmptyVector[A] = | ||
new NonEmptyVector(toVector.reverse) | ||
|
||
def zipWithIndex: NonEmptyVector[(A, Int)] = |
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.
You could use this to override Traverse#zipWithIndex
for NonEmptyVector
.
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.
Done.
@@ -237,6 +255,9 @@ private[data] sealed trait NonEmptyVectorInstances { | |||
override def traverse[G[_], A, B](fa: NonEmptyVector[A])(f: (A) => G[B])(implicit G: Applicative[G]): G[NonEmptyVector[B]] = | |||
G.map2Eval(f(fa.head), Always(Traverse[Vector].traverse(fa.tail)(f)))(NonEmptyVector(_, _)).value | |||
|
|||
override def zipWithIndex[A](fa: NonEmptyVector[A]): NonEmptyVector[(A, Int)] = | |||
fa.zipWithIndex |
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.
this is untested, so I guess that means zipWithIndex is currently lawless.
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.
We could write a test to check if zipWithIndex
is consistent with zipWith(Range(0, size))
:)
Hey @durban, are you still working on this? Or would you like some help? :) |
@LukaJCB I'm not sure what's left to do (if any) ... |
I agree there's not much left :) |
I've rebased and also added more tests for |
LGTM (pending concensus on |
👍 I am fine with the |
I've thought a bit more about this and I think having I'd also be fine with having |
@durban do you still have time to work on this? if you want, I am happy to continue it for you. |
I'd argue that |
Here is my final proposal, it looks that we have to make some trade off or we are going to have to break either NEL or NEV. The trade off I am willing to make here is to allow overload in this particular case. So in NEL we are going to have concat(l: List) //new
concat(nel: NEL)
concatNel(nel: NEL) //new
++(l: List) the concat(v: Vector)
concat(nev: NEV) //new
concatNev(nev: NEV)
++(l: Vector) the In PR #1949
and add to NEV
This might mitigate the @LukaJCB 's concern over an asymmetric symbol concatenation. |
For NEV, you mean |
I think that's a good idea 👍 Edit: Actually I'm not sure right now, the way you put it, it has the symmetric operators for different types and the |
@kailuowang I'm ok with your proposal. If others also agree, I can add it to this PR. |
@LukaJCB the idea is to avoid unnecessary breaking changes. |
I'm good with asymmetry when it means as little breaking changes as possible 👍 |
@kailuowang This is not gonna work:
(For NEL it would work, because that isn't a value class, but at that point we'd lose the consistency.) There are various ugly workarounds for this, but I think they're more ugly than only having |
In previous PRs we've discussed overloading and the general consensus seemed to be that the downsides outweigh the benefits. Personally I'm 👍 for |
Okay, can we add |
@kailuowang Done. I'd skip learning scalafix for now. |
@@ -12,6 +12,7 @@ import cats.data.{NonEmptyList, NonEmptyVector} | |||
import cats.laws.discipline.arbitrary._ | |||
import cats.laws.discipline.{ComonadTests, NonEmptyTraverseTests, MonadTests, ReducibleTests, SemigroupKTests, SerializableTests} | |||
|
|||
@deprecated("to be able to test deprecated methods", since = "1.0.0-RC1") |
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.
Sorry I hate to drag on this but I wouldn't deprecate the whole suite for one test. I'd rather we duplicated the test suite class with just the concat
test in it and deprecate that one.
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.
Done.
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 for this! :)
Hey @durban, sorry to bother you again, but we just need to fix those conflicts, and then we're good to merge! :) If you're too busy, or don't want to invest more time, that's completely okay! |
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.
LGTM, thanks a lot! :) Will merge when Travis is done
haha I beat you @LukaJCB |
There is one notable change: NEL previously had a
concat
which accepted another NEL. To be similar to NEV, I changed this (and addedconcatNel
).The following differences are (intentionally) not addressed:
groupBy
: NEL has one, but I didn't add it to NEV, because I think that it should have anEq
constraint, however implementing that would need aMap
which works withEq
...length
/size
: NEV has alength: Int
and asize: Long
(as an extension method). NEL had asize: Int
and I've addedlength: Int
. (Possiblysize
should be changed toLong
, or simply removed, to be an extension method.)Vector
-specific methods, e.g.,updated
.This fixes #1832 (cc @johnynek).