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 scala.util.control.TailCalls.TailRec instances #3041

Merged
merged 8 commits into from
Nov 6, 2019

Conversation

johnynek
Copy link
Contributor

@johnynek johnynek commented Sep 8, 2019

Adds Defer and Monad instances for TailRec. Now that we don't support 2.10 anymore, we can also re-enable the benchmarks. For my (somewhat slow) machine, TailRec is about 17% faster than Trampoline (but much slower than Eval).

[info] Benchmark                    Mode  Cnt      Score       Error  Units    
[info] TrampolineBench.eval        thrpt    3  16603.447 ± 28185.656  ops/s    
[info] TrampolineBench.stdlib      thrpt    3   4829.133 ±  1911.742  ops/s    
[info] TrampolineBench.trampoline  thrpt    3   4152.917 ±  1948.304  ops/s

The motivation to add this are for users interacting with code that already uses TailRec and for instance interpreting Free into TailRec, or someone who wants to use TailRec with generic code that uses Defer (e.g. ContT).

We could add Semigroup, Monoid and Group to kernel. Since this is further from the main use of TailRec and independent of this current PR, I will not include it here.

@@ -378,6 +378,7 @@ sealed abstract private[cats] class EvalInstances extends EvalInstances0 {
def flatMap[A, B](fa: Eval[A])(f: A => Eval[B]): Eval[B] = fa.flatMap(f)
def extract[A](la: Eval[A]): A = la.value
def coflatMap[A, B](fa: Eval[A])(f: Eval[A] => B): Eval[B] = Later(f(fa))
override def unit: Eval[Unit] = Eval.Unit
Copy link
Contributor Author

Choose a reason for hiding this comment

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

unrelated, but I noticed we could add this and avoid allocations for some folks that use Applicative[F].unit with Eval.

Copy link
Contributor

@travisbrown travisbrown left a comment

Choose a reason for hiding this comment

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

Can you add an object tailRec extends TailRecInstances to the instances package object? Unfortunately we've had to make these version-specific, so you'll have to do it twice.

@@ -378,6 +378,7 @@ sealed abstract private[cats] class EvalInstances extends EvalInstances0 {
def flatMap[A, B](fa: Eval[A])(f: A => Eval[B]): Eval[B] = fa.flatMap(f)
def extract[A](la: Eval[A]): A = la.value
def coflatMap[A, B](fa: Eval[A])(f: Eval[A] => B): Eval[B] = Later(f(fa))
override def unit: Eval[Unit] = Eval.Unit
Copy link
Contributor

Choose a reason for hiding this comment

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

This is unrelated?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes. I added a comment, I just noticed it was missing while looking at Eval.

@@ -30,14 +31,12 @@ class TrampolineBench {
y <- Trampoline.defer(trampolineFib(n - 2))
} yield x + y

// TailRec[A] only has .flatMap in 2.11.
@Benchmark
Copy link
Contributor

Choose a reason for hiding this comment

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

Good catch. Doing a search for "2.10" shows four or five other things like this we should do, but none of them look urgent.

@@ -61,4 +61,7 @@ trait AllInstancesBinCompat4 extends SortedMapInstancesBinCompat1 with MapInstan

trait AllInstancesBinCompat5 extends SortedSetInstancesBinCompat0

trait AllInstancesBinCompat6 extends SortedSetInstancesBinCompat1 with SortedMapInstancesBinCompat2
trait AllInstancesBinCompat6
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't this break bincompat on 2.11? Only with the recent release candidates, I guess, so maybe it's fine?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would assume so. I think we should only bump mima on actual releases (not including any pre-release).

Copy link
Contributor

Choose a reason for hiding this comment

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

@johnynek Right, but it's still useful to know, so we can decide whether we need to publish new pre-releases of cats-effect or Circe after a Cats pre-release, etc.

Copy link
Contributor

Choose a reason for hiding this comment

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

the plan is to drop 2.11 on master immediately after 2.0.0 release (this evening). So we can add this to the root trait.

@codecov-io
Copy link

codecov-io commented Sep 8, 2019

Codecov Report

Merging #3041 into master will increase coverage by 0.03%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master   #3041      +/-   ##
=========================================
+ Coverage   93.57%   93.6%   +0.03%     
=========================================
  Files         371     376       +5     
  Lines        7097    7839     +742     
  Branches      185     228      +43     
=========================================
+ Hits         6641    7338     +697     
- Misses        456     501      +45
Flag Coverage Δ
#scala_version_212 93.88% <100%> (+0.3%) ⬆️
#scala_version_213 91.32% <100%> (?)
Impacted Files Coverage Δ
core/src/main/scala/cats/Eval.scala 98.83% <100%> (+0.01%) ⬆️
core/src/main/scala/cats/instances/tailrec.scala 100% <100%> (ø)
core/src/main/scala/cats/Apply.scala 76.47% <0%> (-2.48%) ⬇️
core/src/main/scala/cats/ApplicativeError.scala 100% <0%> (ø) ⬆️
core/src/main/scala/cats/instances/list.scala 100% <0%> (ø) ⬆️
core/src/main/scala/cats/data/Const.scala 100% <0%> (ø) ⬆️
core/src/main/scala/cats/data/Validated.scala 100% <0%> (ø) ⬆️
core/src/main/scala/cats/SemigroupK.scala 100% <0%> (ø) ⬆️
core/src/main/scala/cats/instances/vector.scala 100% <0%> (ø) ⬆️
.../src/main/scala/cats/syntax/applicativeError.scala 100% <0%> (ø) ⬆️
... and 15 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 6d191a5...e24a602. Read the comment docs.

travisbrown
travisbrown previously approved these changes Sep 9, 2019
Copy link
Contributor

@travisbrown travisbrown left a comment

Choose a reason for hiding this comment

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

Thanks, looks good to me!

@johnynek
Copy link
Contributor Author

@kailuowang any concerns with merging?

@kailuowang
Copy link
Contributor

@johnynek sorry it was too last minute to be carried on the 2.0.0 train.
Now 2.0.0 is released this PR as is breaks BC on 2.11.
The plan is to drop Scala 2.11 on master (I'll find time to do that this week if no one beats me to it), after that we can change this PR to simply extend the AllInstances instead of a BinCompat trait.

@johnynek
Copy link
Contributor Author

@kailuowang I'm confused why we can't merge now, and then when you make the change to merge in the trait and drop 2.11 everything is fine?

@kailuowang
Copy link
Contributor

@johnynek we can't merge the existing bincompat traits because of BC. If we merge this now then we need to
a) remember to move it to a bincompat trait on the new 2.11 branch or remove it.
and
b) on master branch we can either leave it on the bin compat branch or move it to the AllInstance trait.

It's just easier if we do it the other order. I am already working on dropping 2.11 on master so this shouldn't be held for long.
#3051

LukaJCB
LukaJCB previously approved these changes Sep 10, 2019
Copy link
Member

@LukaJCB LukaJCB left a comment

Choose a reason for hiding this comment

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

LGTM

@kailuowang kailuowang dismissed stale reviews from LukaJCB and travisbrown via 71ac6a4 October 18, 2019 18:51
kailuowang
kailuowang previously approved these changes Oct 18, 2019
LukaJCB
LukaJCB previously approved these changes Oct 18, 2019
@travisbrown travisbrown dismissed stale reviews from LukaJCB and kailuowang via cc304ca November 5, 2019 11:47
@travisbrown
Copy link
Contributor

Just formatted, which should fix the build.

@travisbrown travisbrown added this to the 2.1.0-RC1 milestone Nov 5, 2019
@travisbrown
Copy link
Contributor

Now there's a bincompat error, and it looks legit. I don't know how this ever passed, given that adding a val to a trait should always have been a breaking change?

@johnynek
Copy link
Contributor Author

johnynek commented Nov 5, 2019

I guess the idea that we can just add new traits to AllInstances in 2.0.0 is wrong in some way.

@travisbrown
Copy link
Contributor

@johnynek We can, just not as vals. I've got a bincompat version here (or if you don't mind I could just push to this branch instead): #3127

@johnynek
Copy link
Contributor Author

johnynek commented Nov 5, 2019

I would welcome your push, as my vanity has a slight preference for this PR be the one merged.

@johnynek
Copy link
Contributor Author

johnynek commented Nov 5, 2019

Thank you for doing this work.

@travisbrown
Copy link
Contributor

@johnynek Pushed, thanks! (They'd be your commits either way. 😄)

@johnynek
Copy link
Contributor Author

johnynek commented Nov 6, 2019

👍

Thanks @kailuowang and @travisbrown

@LukaJCB LukaJCB merged commit fc7b8b9 into master Nov 6, 2019
@larsrh larsrh deleted the oscar/add_tailrec_monad branch November 9, 2019 17:26
gagandeepkalra added a commit to gagandeepkalra/cats that referenced this pull request Feb 29, 2020
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