Skip to content
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

Add some instances we were missing. #1878

Merged
merged 9 commits into from
Sep 2, 2017

Conversation

non
Copy link
Contributor

@non non commented Aug 31, 2017

This commit adds support for some types:

  • Ordering, PartialOrdering, and Equiv
  • scala.concurrent.duration.Duration
  • scala.collection.immutable.Queue

The ordering types should be relatively uncontroversial.

I chose to support Duration even though arguably FiniteDuration is a
bit better behaved. This isn't the worst group we support, and I feel
like it's possible that folks will really benefit from these instances.

Queue is probably the most interesting immutable data structure we
didn't already support. I based its instances on those for List,
rewriting things to use .isEmpty and .dequeue instead of
pattern-matching.

We could potentially try to support some of the other concrete
collection types (e.g. HashMap, TreeMap, IntMap, SortedMap, etc.)
which might not be a bad idea. I haven't done that here.

I added tests for Queue and Duration, but have not (yet) tested the
pretty trivial contravariant instances.

Fixes #1853.

This commit adds support for some types:

 - Ordering, PartialOrdering, and Equiv
 - scala.concurrent.duration.Duration
 - scala.collection.immutable.Queue

The ordering types should be relatively uncontroversial.

I chose to support Duration even though arguably FiniteDuration is a
bit better behaved. This isn't the worst group we support, and I feel
like it's possible that folks will really benefit from these instances.

Queue is probably the most interesting immutable data structure we
didn't already support. I based its instances on those for List,
rewriting things to use .isEmpty and .dequeue instead of
pattern-matching.

We could potentially try to support some of the other concrete
collection types (e.g. HashMap, TreeMap, IntMap, SortedMap, etc.)
which might not be a bad idea. I haven't done that here.

I added tests for Queue and Duration, but have not (yet) tested the
pretty trivial contravariant instances.
@non
Copy link
Contributor Author

non commented Aug 31, 2017

Looks like this is failing a binary compatibility check.

@kailuowang
Copy link
Contributor

There are a few other tickets blocked by kernel bin compat, (#1712, #1527). @denisrosset suggested in gitter that it's no big deal for the spire community to break in the 1.0 release, I just asked in the algebird gitter room. @johnynek suggested that he'd rather not break. Is that something we can reevaluate? If not what's the alternative? (move all these to cats.core or a new module?)

@non
Copy link
Contributor Author

non commented Aug 31, 2017

@kailuowang I think if we leave DurationInstances and QueueInstances out of the kernel's all.scala that should fix the kernel issues, no? I'll try that here.

@codecov-io
Copy link

codecov-io commented Aug 31, 2017

Codecov Report

Merging #1878 into master will increase coverage by 0.19%.
The diff coverage is 98.38%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1878      +/-   ##
==========================================
+ Coverage   94.97%   95.17%   +0.19%     
==========================================
  Files         241      248       +7     
  Lines        4199     4349     +150     
  Branches      106      122      +16     
==========================================
+ Hits         3988     4139     +151     
+ Misses        211      210       -1
Impacted Files Coverage Δ
...a/cats/laws/discipline/NonEmptyTraverseTests.scala 100% <ø> (ø) ⬆️
...in/scala/cats/laws/discipline/ReducibleTests.scala 100% <ø> (ø) ⬆️
core/src/main/scala/cats/instances/duration.scala 0% <0%> (ø)
core/src/main/scala/cats/instances/ordering.scala 100% <100%> (ø)
core/src/main/scala/cats/instances/queue.scala 100% <100%> (ø)
...ain/scala/cats/laws/discipline/TraverseTests.scala 100% <100%> (ø) ⬆️
core/src/main/scala/cats/data/NonEmptyVector.scala 100% <100%> (ø) ⬆️
laws/src/main/scala/cats/laws/FoldableLaws.scala 100% <100%> (ø) ⬆️
core/src/main/scala/cats/instances/order.scala 100% <100%> (ø) ⬆️
...rc/main/scala/cats/laws/discipline/Arbitrary.scala 92.06% <100%> (-0.13%) ⬇️
... and 20 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d85cc86...adcb06b. Read the comment docs.

@non
Copy link
Contributor Author

non commented Aug 31, 2017

So with that commit we maintain binary compatibility for kernel.

@kailuowang
Copy link
Contributor

so shall we have a cats.instances.extra to place all the new instances helpers or something?

@non
Copy link
Contributor Author

non commented Aug 31, 2017

@kailuowang Let's wait and see how many there are. For now I think we should just add them to all.scala commented out, and then make a decision just before the 1.0 release.

(Looks like last error was formatting, pushing a fix now.)

@non
Copy link
Contributor Author

non commented Aug 31, 2017

In cases where we are adding instances for a new type, the approach I used should be good I think. For adding instances to an existing type (i.e. where we already have a trait in kernel and can't add to it without breaking compat), let's just put them in core with a comment that they could be in kernel except for bincompat.

What do you think @johnynek?

@kailuowang
Copy link
Contributor

kailuowang commented Aug 31, 2017

@non 👍 on deciding later. I just created a dedicated issue #1879 for it.

/** Derive an `Ordering` for `B` given an `Ordering[A]` and a function `B => A`.
*
* Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping)
*/
Copy link
Contributor

@kailuowang kailuowang Aug 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a related note (not suggesting we should change anything here), we do have an Inject with laws, user could use it to test if a function f: A => B is injective, by creating a prj: B => Option[A] and an Inject[A, B] using these two, then testing the law against this Inject instance.

{
  implicit val inject = new Inject[A, B] { 
     val inj = f 
     val prj : B => Option[A] = ???
  }
 checkAll("Inject[A, B]", InjectTests[A, B].inject)
}

If you think this would be a good idea, we could potentially add it to the cats-testkit.

import cats.functor.Contravariant

trait PartialOrderingInstances {
implicit val catsFunctorContravariantForPartialOrdering: Contravariant[PartialOrdering] =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note sure if this instance is tested.


trait QueueInstances extends cats.kernel.instances.QueueInstances {

implicit val catsStdInstancesForQueue: Traverse[Queue] with Alternative[Queue] with Monad[Queue] with CoflatMap[Queue] =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bunch of these overrides are not tested. I am not sure how big a deal it is since they don't seem to be tested for the list instance either.

@non
Copy link
Contributor Author

non commented Aug 31, 2017

@kailuowang I can probably get us test coverage on all of this if we're willing to wait until later today or tonight.

@@ -93,6 +136,7 @@ class LawTests extends FunSuite with Discipline {
laws[OrderLaws, List[String]].check(_.order)
laws[OrderLaws, Vector[Int]].check(_.order)
laws[OrderLaws, Stream[Int]].check(_.order)
laws[OrderLaws, Queue[Int]].check(_.order)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find OrderLaws test with Duration?

Copy link
Contributor

@johnynek johnynek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is fine from a binary break-age point of view. We don't directly depend on the instances in algebird.

trait OrderingInstances {

implicit val catsFunctorContravariantForOrdering: Contravariant[Ordering] =
new Contravariant[Ordering] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't this be ContravariantCartesian as well? Just use left to right ordering?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. Initially I was uncertain about adding this but ended up going for it.


trait PartialOrderingInstances {
implicit val catsFunctorContravariantForPartialOrdering: Contravariant[PartialOrdering] =
new Contravariant[PartialOrdering] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't this be contravariantCartesian using left to right ordering?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. Initially I was uncertain about adding this but ended up going for it.

@non
Copy link
Contributor Author

non commented Sep 1, 2017

Added a bunch more tests, and ended up doing some refactors to other parts of the tests to remove some boilerplate.

It's sort of terrifying to realize that we're closing in on 1.0 and there's still so much potential polish we could do. 😛

PartialOrder.from[A]((_: A, _: A) => -1.0),
PartialOrder.from[A]((_: A, _: A) => 0.0),
PartialOrder.from[A]((_: A, _: A) => 1.0)))
Arbitrary(getArbitrary[Int => Double].map(f => new PartialOrder[A] {
Copy link
Contributor

@kailuowang kailuowang Sep 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 this makes a lot more sense

@kailuowang
Copy link
Contributor

@non I wonder if you and/or @ceedubs have time to quickly skim through all the code in cats-core to spot all the obvious polish needed before 1.0 release?

@non
Copy link
Contributor Author

non commented Sep 1, 2017

The previous test failure was legit: by testing some of the Foldable and Traversable methods against their references, I found two instances (Map[K, ?] and NonEmptyVector) which were treating negative indices incorrectly.

@non
Copy link
Contributor Author

non commented Sep 1, 2017

I think this is finally ready-to-go test coverage-wise.

@johnynek
Copy link
Contributor

johnynek commented Sep 1, 2017

👍

Thanks for tackling this before 1.0!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants