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

move instances into separate trait #1659

Merged
merged 4 commits into from
May 28, 2017

Conversation

yilinwei
Copy link
Contributor

@yilinwei yilinwei commented May 11, 2017

#1657

The current instances sit in the object of Contravariant.

This means that you can't get an implicit of a subclass - implicitly[Invariant[Order]] doesn't work because the instance is not in the companion object of Order or Invariant and the methods such as imap won't work either.

I would argue that for the behaviour to be consistent with the other instances, these should be moved into separate traits.

Doing a quick grep for Kernel...Instances

  • Cartesian
  • InvariantMonoidal
  • ContravariantCartesian
  • Contravariant
  • Invariant

are affected.

@codecov-io
Copy link

codecov-io commented May 11, 2017

Codecov Report

Merging #1659 into master will decrease coverage by <.01%.
The diff coverage is 87.5%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1659      +/-   ##
==========================================
- Coverage   93.96%   93.95%   -0.01%     
==========================================
  Files         241      246       +5     
  Lines        4091     4087       -4     
  Branches      160      157       -3     
==========================================
- Hits         3844     3840       -4     
  Misses        247      247
Impacted Files Coverage Δ
core/src/main/scala/cats/functor/Invariant.scala 71.42% <ø> (-6.35%) ⬇️
...e/src/main/scala/cats/ContravariantCartesian.scala 66.66% <ø> (-16.67%) ⬇️
core/src/main/scala/cats/Cartesian.scala 100% <ø> (ø) ⬆️
core/src/main/scala/cats/InvariantMonoidal.scala 0% <ø> (-77.78%) ⬇️
...re/src/main/scala/cats/functor/Contravariant.scala 100% <ø> (ø) ⬆️
...main/scala/cats/laws/discipline/FlatMapTests.scala 100% <ø> (ø) ⬆️
...e/src/main/scala/cats/instances/partialOrder.scala 100% <100%> (ø)
core/src/main/scala/cats/instances/eq.scala 100% <100%> (ø)
core/src/main/scala/cats/instances/order.scala 100% <100%> (ø)
core/src/main/scala/cats/instances/semigroup.scala 75% <75%> (ø)
... and 8 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 80d56e6...fea3b25. Read the comment docs.

@ceedubs
Copy link
Contributor

ceedubs commented May 11, 2017

@yilinwei thanks! I think that you raise a good point about implicitly[Invariant[Order]] not working.

While import cats.implicits._ is the approach that we recommend to people, we also support piecemeal imports such as cats.instances.string._. I wonder if we should provide something similar for these instances? If so I'm not quite sure how one should do that. cats.instances.kernel.order._ or something? It seems kind of awkward. And it makes me wonder if instead of trait EqInstances you should have trait KernelEqInstances or something.

@edmundnoble
Copy link
Contributor

I like cats.instances.order and the approach in this PR. We provide instances originating in kernel from instances._ already with mixins (see instances.bitSet); I think that fits well with providing instances for types provided from kernel.

@yilinwei
Copy link
Contributor Author

@ceedubs

I forgot about the piecemeal imports; I think we should definitely include them. I also agree with @edmundnoble that they should sit under instances rather than instances.kernel.

@ceedubs
Copy link
Contributor

ceedubs commented May 12, 2017

Thanks for adding the piecemeal imports @yilinwei. This looks good to me.

It's a little bit of a head-scratcher to think about the fact that MonoidInstances and import cats.instances.monoid._ don't actually include any Monoid[A] instances. Instead they include functor instances for monoids :). However, I do think that this setup is consistent.

codecov is legitimately reporting a slight code coverage drop on this PR. While it's pretty trivial, it may be good to hit the new piecemeal imports in unit tests to make sure that they work as intended. I also think that it would be good to have the unit tests check some implicit resolutions for things like the Invariant[Order] that was the motivation for this PR.

@yilinwei
Copy link
Contributor Author

@ceedubs I feel those tests ought to be autogenerated, ideally something along the lines of,

canResolve[F, TC] { import ... }

should reify into implicitly[TC1]; implicitly[TC2] .... for the whole of the hierarchy.

wdyt?

@yilinwei
Copy link
Contributor Author

yilinwei commented May 16, 2017

@ceedubs

I've committed an example of what I mean;

The macro generates an implicitly for each typeclass in the hierarchy with the import and any implicit vals in scope.

There are two problems at the moment though;

  1. I can't quite work out how to do test->test dependencies since I'm not too familiar with the javascript cross build. The macro should definitely sit in the test directory.
  2. More importantly, scalac flags the import as unused when it's definitely being used. I've disabled the flag for now; but I'd really like to be able to turn it back on if anyone has any ideas.

@peterneyens
Copy link
Collaborator

I like the idea of testing the resolution of all the type class instances in the hierarchy.
It would be nice to replace code like this.

@yilinwei
Copy link
Contributor Author

I've simplified the macro to just do the implictly expansion because scalac was doing funny things with the imports.

The names are implicitlyH which stands for implicitlyHierarchy and implicitlyHK which stands for implicitlyHierarchyKind. I'm not particularly happy with the name because H usually stands for heterogenous and could be confusing.

I still need to deal with project structures, but the scalac flag problem should go away.

@peterneyens I've added an example for the WriterT to show it works correctly.

@kailuowang
Copy link
Contributor

My original concern is that we might have incentive to go the other direction, i.e. move these instance into the companion objects for maintainability of binary compatibility. #1683
After some inspection of the instances being moved in this PR. It doesnt seem to me that there is a good chance of changing these traits. So 👍 from me. As for automatically generated tests, can we attack them in a separate PR?

@kailuowang kailuowang added this to the 1.0.0-MF milestone May 25, 2017
@kailuowang kailuowang mentioned this pull request May 25, 2017
26 tasks
@yilinwei
Copy link
Contributor Author

@kailuowang Sure; I was more hoping for feedback on whether people like this approach before taking it any further.

Regardless I'll separate the changes from the original ones tomorrow with the additional tests suggested by @ceedubs.

@djspiewak
Copy link
Member

👍 from me. So this is good for merge once @yilinwei is finished with it.

@kailuowang
Copy link
Contributor

👍 modular build green

class EqTests extends FunSuite {
{
import cats.implicits._
implicitly[Invariant[Eq]]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just nitpicking, but we don't need implicitly in all these tests as simulacrum generates an apply in the companion object. Should we just write Invariant[Eq], Invariant[Monoid], ...?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed

val empty = f(fa.empty)
def combine(x: B, y: B): B = f(fa.combine(g(x), g(y)))
override def combineAll(bs: TraversableOnce[B]): B =
f(fa.combineAll(bs.map(g)))
Copy link
Contributor

Choose a reason for hiding this comment

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

This line was not covered in the original code, which is a bit surprising to me. We can probably address it in a different PR. Just want to keep a note here.

def imap[A, B](fa: Semigroup[A])(f: A => B)(g: B => A): Semigroup[B] = new Semigroup[B] {
def combine(x: B, y: B): B = f(fa.combine(g(x), g(y)))
override def combineAllOption(bs: TraversableOnce[B]): Option[B] =
fa.combineAllOption(bs.map(g)).map(f)
Copy link
Contributor

Choose a reason for hiding this comment

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

This line was not covered in the original code, which is a bit surprising to me. We can probably address it in a different PR. Just want to keep a note here.

def pure[A](a: A): Semigroup[A] = new Semigroup[A] {
def combine(x: A, y: A): A = a
override def combineAllOption(as: TraversableOnce[A]): Option[A] =
if (as.isEmpty) None else Some(a)
Copy link
Contributor

Choose a reason for hiding this comment

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

This line was not covered in the original code. We can probably address it in a different PR. Just want to keep a note here.

@peterneyens
Copy link
Collaborator

Merging with three thumbs up. Thanks @yilinwei!

@peterneyens peterneyens merged commit b722f2b into typelevel:master May 28, 2017
LukaJCB pushed a commit that referenced this pull request Oct 4, 2017
* cats.kernel.Hash and related instances (#1690)

* Hash laws

* all test passed

* Hash instances for tuples

* introduce implicit precedence in KernelBoiler: Order > PartialOrder > Eq; Hash > Eq.

* Add type alias in cats._; Add contravariant instance for `Hash`

* HashFunctions extends EqFunctions

* Move contravariant instances to separate trait, in accordance with (#1659)

* revert name change

* move EitherInstances1#EitherEq out

* Optimize hash computation on case classes without allocating a new object

* fixing the problem in CI build: method catsKernelStdOrderForChar()cats.kernel.instances.CharOrder in trait cats.kernel.instances.CharInstances has a different result type in current version, where it is cats.kernel.Order rather than cats.kernel.instances.CharOrder

* Full compliance with how Scala generates hash codes on case classes; +SetHash

* Cartesian[Hash]

* ContravariantCartesian[Hash]

* ContravariantCartesian[Hash]; Hash.fromHashing

* style issues

* remove unused import

* some test cases

* some test cases

* +test for Contravariant[Hash]

* +test for Contravariant[Hash]

* Add NEL/NEV one (#1707)

`NonEmptyList.one` is analogous to `_.pure[NonEmptyList]`.

Alternative for `NonEmptyList.of(x)` where you don't pay the price of
the varargs, which isn't used.

* move instances into separate trait (#1659)

* move instances into separate trait

* adding separate objects for piecemeal imports

* Adding implicit resolution tests for piecemeal imports for hierarchy

* Removing explicit implicitly and using apply method

* cats.kernel.Hash and related instances (#1690)

* Hash laws

* all test passed

* Hash instances for tuples

* introduce implicit precedence in KernelBoiler: Order > PartialOrder > Eq; Hash > Eq.

* Add type alias in cats._; Add contravariant instance for `Hash`

* HashFunctions extends EqFunctions

* Move contravariant instances to separate trait, in accordance with (#1659)

* revert name change

* move EitherInstances1#EitherEq out

* Optimize hash computation on case classes without allocating a new object

* fixing the problem in CI build: method catsKernelStdOrderForChar()cats.kernel.instances.CharOrder in trait cats.kernel.instances.CharInstances has a different result type in current version, where it is cats.kernel.Order rather than cats.kernel.instances.CharOrder

* Full compliance with how Scala generates hash codes on case classes; +SetHash

* Cartesian[Hash]

* ContravariantCartesian[Hash]

* ContravariantCartesian[Hash]; Hash.fromHashing

* style issues

* remove unused import

* some test cases

* some test cases

* +test for Contravariant[Hash]

* +test for Contravariant[Hash]

* cats.kernel.Hash and related instances (#1690)

* Hash laws

* all test passed

* Hash instances for tuples

* introduce implicit precedence in KernelBoiler: Order > PartialOrder > Eq; Hash > Eq.

* Add type alias in cats._; Add contravariant instance for `Hash`

* HashFunctions extends EqFunctions

* Move contravariant instances to separate trait, in accordance with (#1659)

* revert name change

* move EitherInstances1#EitherEq out

* Optimize hash computation on case classes without allocating a new object

* fixing the problem in CI build: method catsKernelStdOrderForChar()cats.kernel.instances.CharOrder in trait cats.kernel.instances.CharInstances has a different result type in current version, where it is cats.kernel.Order rather than cats.kernel.instances.CharOrder

* Full compliance with how Scala generates hash codes on case classes; +SetHash

* Cartesian[Hash]

* ContravariantCartesian[Hash]

* ContravariantCartesian[Hash]; Hash.fromHashing

* style issues

* remove unused import

* some test cases

* some test cases

* +test for Contravariant[Hash]

* +test for Contravariant[Hash]

* Fix duplication error and style error

* fix merge error

* remove instance for Cartesian[Hash]: it does not satisfy associativity

* +identityHash, +`hash` postfix method

* all tests passed

* increase coverage

* accidentally removed plugin, restore it

* all tests passed

* increase coverage

* increase coverage, ## => hashCode, kernelBoiler

* suppress mimaReportBinaryIssues

* Remove cats.functor

* Remove cats.functor
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.

7 participants