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

Consistency for ops classes #1456

Merged
merged 1 commit into from
Apr 13, 2017

Conversation

edmundnoble
Copy link
Contributor

@edmundnoble edmundnoble commented Nov 6, 2016

  1. Extend AnyVal when possible, unless there are only macro ops
    1a. Don't take implicit params in the ops class param list, again unless
    there are macro ops, or they can't extend AnyVal.
    (there is one exception to this and a comment explaining it; it's EqSyntax)
  2. Make all conversions to ops classes final. They are all declared in
    traits, so users with their own syntax hierarchy have no chance of
    inlining unless they are marked final. Plus, it's consistent.
  3. Make all ops class constructor fields private by default, to avoid
    polluting the namespace of the type.
    Edit: 3 is not possible for Scala 2.10, so it was removed from this PR.

@codecov-io
Copy link

codecov-io commented Nov 6, 2016

Codecov Report

Merging #1456 into master will not change coverage.
The diff coverage is 91.66%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #1456   +/-   ##
=======================================
  Coverage   93.08%   93.08%           
=======================================
  Files         250      250           
  Lines        3989     3989           
  Branches      135      136    +1     
=======================================
  Hits         3713     3713           
  Misses        276      276
Impacted Files Coverage Δ
core/src/main/scala/cats/syntax/semigroupk.scala 0% <ø> (ø) ⬆️
core/src/main/scala/cats/syntax/semigroup.scala 0% <ø> (ø) ⬆️
core/src/main/scala/cats/syntax/bitraverse.scala 50% <ø> (ø) ⬆️
core/src/main/scala/cats/syntax/monadFilter.scala 0% <ø> (ø) ⬆️
.../src/main/scala/cats/syntax/applicativeError.scala 100% <ø> (ø) ⬆️
...ore/src/main/scala/cats/syntax/contravariant.scala 0% <ø> (ø) ⬆️
core/src/main/scala/cats/syntax/order.scala 0% <ø> (ø) ⬆️
core/src/main/scala/cats/syntax/monadError.scala 100% <ø> (ø) ⬆️
...re/src/main/scala/cats/syntax/traverseFilter.scala 0% <ø> (ø) ⬆️
core/src/main/scala/cats/syntax/apply.scala 100% <ø> (ø) ⬆️
... and 26 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 9c3130e...22d15ea. Read the comment docs.

@johnynek
Copy link
Contributor

johnynek commented Nov 6, 2016

Can we add these style rules to a doc somewhere? Ideally, we could tool something like wart-remover to check them.

@johnynek
Copy link
Contributor

johnynek commented Nov 6, 2016

In spirit, I like this, but I do hope sooner or later we get serious about preserving some binary compatibility. This has a large binary incompatibility cross-section.

@kailuowang
Copy link
Contributor

kailuowang commented Nov 7, 2016

@edmundnoble thanks very much for this! Sorry about raising the val in Ops class issue which probably wasted quite some time of yours. I suspected that 2.10 might be the cause for not making those private at the first place but didn't get the chance to verify.
I agree there is value in documenting these style rules including issue that 2.10 preventing the self val to be private.

@edmundnoble edmundnoble force-pushed the consistent-ops-classes branch 2 times, most recently from 957317b to 874c331 Compare November 7, 2016 03:13
@edmundnoble
Copy link
Contributor Author

I added a lil something in this PR for the ops classes guidelines, while I was fixing the merge conflict. If it's better somewhere else I can take it right back out.

@kailuowang
Copy link
Contributor

LGTM, 👍 Thanks again

@johnynek
Copy link
Contributor

johnynek commented Nov 7, 2016

I added breaking change to this since it breaks binary compatibility (not source in most cases). I think that is appropriate.

@ceedubs
Copy link
Contributor

ceedubs commented Jan 6, 2017

Given that we are merging other binary-incompatible changes, I think that I give this a 👍. Notably this is different than Simulacrum, which doesn't use value classes (if I recall correctly). @mpilquist do you think that value classes are appropriate in these cases?

@johnynek are you okay with us merging the binary-incompatible change? I've been MIA for a while, so to be honest I don't really know what current plans are on Cats releases/compatibility.

@edmundnoble edmundnoble force-pushed the consistent-ops-classes branch from 874c331 to 5e57e35 Compare January 6, 2017 18:26
@edmundnoble
Copy link
Contributor Author

Rebased.

@johnynek
Copy link
Contributor

johnynek commented Jan 7, 2017

Two things:

  1. binary compatibility is not binary (pun intended). The more incompatible changes we make, the greater the chance we cause an issue for a user.

  2. we should investigate using abstract class much more than trait, since it is much friendlier for binary compatibility. For linear hierarchies which we often use for priorities, we could probably use more abstract classes.

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.

looks good. Noted a couple of untested methods this trips over (and thus the diff has lower coverage than our current average).


def <*[B](fb: F[B])(implicit F: Functor[F]): F[A] = F.map(typeClassInstance.product(self, fb)) { case (a, b) => a }
final def <*[B](fb: F[B])(implicit F: Functor[F]): F[A] = F.map(typeClassInstance.product(self, fb)) { case (a, b) => a }
Copy link
Contributor

Choose a reason for hiding this comment

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

codecov says this method is untested.

final class MonoidOps[A: Monoid](lhs: A) {
def isEmpty(implicit eq: Eq[A]): Boolean = Monoid[A].isEmpty(lhs)(eq)
final class MonoidOps[A](val lhs: A) extends AnyVal {
def isEmpty(implicit A: Monoid[A], eq: Eq[A]): Boolean = A.isEmpty(lhs)(eq)
Copy link
Contributor

Choose a reason for hiding this comment

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

this method is untested.

@edmundnoble edmundnoble force-pushed the consistent-ops-classes branch from 5e57e35 to 5296069 Compare January 7, 2017 23:45
@kailuowang kailuowang added this to the 1.0.0-MF milestone Apr 11, 2017
@kailuowang
Copy link
Contributor

@edmundnoble would you like to resolve conflicts and merge (it has two sign-offs)?

@edmundnoble
Copy link
Contributor Author

Gotcha. Will do today.

1. Extend AnyVal when possible, unless there are macro ops
1a. Don't take implicit params in the ops class param list, again unless
    there are macro ops.
2. Make all conversions to ops classes final. They are all declared in
   traits, so users with their own syntax hierarchy have no chance of
   inlining unless they are marked final. Plus, it's consistent.
3. Make all ops class constructor fields private by default, to avoid
   polluting the namespace of the type.

Remove private val part, because scala 2.10 doesn't support it

Ops class guidelines

Add CartesianTest
@edmundnoble edmundnoble force-pushed the consistent-ops-classes branch from 5296069 to 22d15ea Compare April 13, 2017 04:44
@edmundnoble edmundnoble merged commit 19c3a37 into typelevel:master Apr 13, 2017
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