-
-
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
Treat Stream and LazyList as different types #2983
Treat Stream and LazyList as different types #2983
Conversation
case Left(a) => Some((None, fn(a).iterator ++ it)) | ||
case Right(b) => Some((Some(b), it)) | ||
} | ||
else |
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 Scalafmt, which doesn't seem to be running for 2.13-specific code?
Codecov Report
@@ Coverage Diff @@
## master #2983 +/- ##
==========================================
- Coverage 93.83% 93.75% -0.08%
==========================================
Files 369 366 -3
Lines 7074 6922 -152
Branches 189 179 -10
==========================================
- Hits 6638 6490 -148
+ Misses 436 432 -4
Continue to review full report at Codecov.
|
@@ -0,0 +1,62 @@ | |||
package cats | |||
|
|||
package object instances { |
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 use an abstract class for objects from both scala specific versions to inherit from and remove the duplication?
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.
Not without dropping in some lazy val
s. Here's a minimization:
package foo
package object bar extends BarPackage
package bar {
abstract class BarPackage {
object baz extends Baz
}
trait Baz {
val x = foo.bar.baz
}
}
Referring to baz
will stack overflow.
@@ -209,7 +209,7 @@ sealed abstract private[data] class OneAndLowPriority4 { | |||
fa.head | |||
|
|||
def map[A, B](fa: OneAnd[LazyList, A])(f: A => B): OneAnd[LazyList, B] = | |||
fa.map(f) | |||
fa.map(f)(crossVersionInstancesForLazyList) |
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.
so for a user who needs to cross compile, they either have to create this crossVersionInstancesForLazyList
themselves or have to write version specific code for every import cats.instances.stream._
they have in the past?
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 have a suggestion in my comment below.
I am bit concerned with the ergonomics for cross compiling users who migrated away from Stream on 2.13. |
@kailuowang Personally I think the alias is a bad idea in general. I've only included this |
If you can make all I'd argue that we either leave as is, or we just go ahead and really make ALL Either way, I think the |
One more thing, if we make all Stream dependent code version specific we then add back the stream instances on 2.13 and have them deprecated. |
My goal was to remove any public conflation of the two types. My position is that I think conflating the two is a mistake, but as long as Cats doesn't force that decision on me I don't really care about the implementation.
How should we decide on this? |
But there is still public conflation (e.g. ZipStream and parallel instance for stream. ), There doesn't seem to be a lot left with the changes from this PR, completely removing the conflation with version specific code seems a reasonable effort. We can hold a vote among the maintainers, because if we chose duplication it will be maintainers burden. |
Okay! How do we call for a vote? I'm happy to make the remaining changes if we decide to go that route. |
Issue created for vote |
@@ -523,6 +523,7 @@ lazy val kernelLaws = crossProject(JSPlatform, JVMPlatform) | |||
.settings(scoverageSettings) | |||
.settings(disciplineDependencies) | |||
.settings(testingDependencies) | |||
.settings(scalacOptions in Test := (scalacOptions in Test).value.filter(_ != "-Xfatal-warnings")) |
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 necessary because we now have deprecation warnings for Stream
on 2.13.
type NonEmptyStream[A] = OneAnd[Stream, A] | ||
|
||
@deprecated("2.0.0-RC2", "Use NonEmptyLazyList") | ||
def NonEmptyStream[A](head: A, tail: Stream[A]): NonEmptyStream[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.
Note that we can't have the default argument here that we have on 2.11 and 2.12, since it results in a deprecation warning (which is clearly a compiler bug).
This PR is becoming a nightmare, but I think it's ready for review. Some notes:
There is one difference between @deprecated("2.0.0-RC2", "Use NonEmptyLazyList")
def NonEmptyStream[A](head: A, tail: Stream[A]): NonEmptyStream[A] = ... While on 2.11-12 we have: def NonEmptyStream[A](head: A, tail: Stream[A] = Stream.empty): NonEmptyStream[A] = ... I removed the default argument on 2.13 because it results in a deprecation warning, which is a compiler bug—it clearly shouldn't warn. We could alternatively leave the default argument and use the silencer scalac plugin to ignore this one (spurious) warning, but that seemed like overkill for a deprecated method where we have no bincompat / source compat obligations. |
trait LazyListInstances extends StreamInstances with StreamInstancesBinCompat0 { | ||
val catsStdInstancesForLazyList = catsStdInstancesForStream | ||
} | ||
private[instances] trait LazyListInstances |
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.
Is this still needed?
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 we don't want two copies of cats/instances/all.scala
we do need it.
(I guess you could argue that we have two copies of everything else at this point so we might as well do it here.)
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.
didn't you already add version specific copies for cats/instances/package.scala?
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.
Yes, but the definition of AllInstances
in all.scala
also needs to bring in the LazyList
instances on 2.13.
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.
Ah i see. I didn't see you were able to deprecate all the methods in StreamInstance
to avoid deprecating the trait.
Since it confused me a bit, I think we might just as well create two copies for it so that hopefully we can get rid off all Stream/LazyList
related ScalaVersionSpecific
stuff in non test code?
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.
Sure, I can go ahead and do this.
import cats.kernel.Semigroup | ||
import cats.syntax.either._ | ||
import cats.{~>, Applicative, Apply, FlatMap, Functor, Monad, NonEmptyParallel, Parallel} | ||
import kernel.compat.scalaVersionSpecific._ |
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.
In all version specific code (i.e. not being cross compiled), you shouldn't need to import a compat.scalaVersionSpecific._
right? which also means that you shouldn't need the @suppressUnusedImportWarningForScalaVersionSpecific
below as well.
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 think you're right. Let me try removing all of these in the version-specific source trees.
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.
In some cases we might still want to use some of this stuff to minimize the diff between version-specific files? Like IterableOnce
? I'm not sure—let me try it.
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 catching that, @kailuowang—there were only a couple of place we were using IterableOnce
or lazyZip
in version-specific code. Just pushed a commit removing scalaVersionSpecific
in all version-specific code (except where it's defined).
Okay, after a bunch of slow experiments today, here's what I've figured out about the CI failure:
|
Thanks for the trouble shooting and update. |
This reverts commit 9b28588.
@kailuowang Sounds reasonable. I've just pushed the change. I've also dropped the explicit |
Thanks for this monster of an effort 👍 |
@@ -303,22 +303,6 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest { | |||
} | |||
} | |||
|
|||
test("ParMap over Stream should be consistent with zip") { |
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 couldn't find the Stream version of this test any more?
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.
Oh, ouch, that's my fault. Fixed now.
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.
Well, not quite, one second…
@@ -343,12 +327,6 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest { | |||
} | |||
} | |||
|
|||
test("ParTupled of Stream should be consistent with ParMap of Tuple.apply") { |
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 couldn't find the Stream version of this test any more?
@@ -361,12 +339,6 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest { | |||
} | |||
} | |||
|
|||
test("ParTupled of Stream should be consistent with zip") { |
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 couldn't find the Stream version of this test any more?
@@ -445,8 +417,6 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest { | |||
checkAll("NonEmptyParallel[Vector, ZipVector]", | |||
NonEmptyParallelTests[Vector, ZipVector].nonEmptyParallel[Int, String]) | |||
checkAll("NonEmptyParallel[List, ZipList]", NonEmptyParallelTests[List, ZipList].nonEmptyParallel[Int, String]) | |||
// Can't test Parallel here, as Applicative[ZipStream].pure doesn't terminate | |||
checkAll("Parallel[Stream, ZipStream]", NonEmptyParallelTests[LazyList, ZipStream].nonEmptyParallel[Int, String]) |
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 couldn't find the Stream version of this test any more?
@@ -115,7 +115,7 @@ class RegressionSuite extends CatsSuite { | |||
// shouldn't have ever evaluted validate(8) | |||
checkAndResetCount(3) | |||
|
|||
LazyList(1, 2, 6, 8).traverse(validate) should ===(Either.left("6 is greater than 5")) | |||
Stream(1, 2, 6, 8).traverse(validate) should ===(Either.left("6 is greater than 5")) |
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 don't know much of these regression tests, but are we sure that LazyList
doesn't need them (couldn't find the LazyList
version)?
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 omitted these intentionally, but looking more closely I'm surprised the property being tested isn't covered by the Traverse
laws, and we probably do want it for LazyList
. Will add now.
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 again!
Thanks for the thorough review! |
A quick implementation of the second proposal in #2982.This became a much deeper fix for #2982 after conversation and a vote in #2991. In the initial version it only removed the aliasing in instances, but now it removes the aliasing altogether.