-
-
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
Avoid syntax methods in implementations in cats-core #3263
Conversation
For the record this isn't something I feel particularly strongly about—I just thought it was worth seeing how much noise this would add, and it turns out it isn't much. I'm happy to change the PR to only include the easy replacements if people would prefer that. |
Codecov Report
@@ Coverage Diff @@
## master #3263 +/- ##
==========================================
+ Coverage 93.08% 93.09% +0.01%
==========================================
Files 376 376
Lines 7428 7483 +55
Branches 196 197 +1
==========================================
+ Hits 6914 6966 +52
- Misses 514 517 +3
Continue to review full report at Codecov.
|
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.
Interestingly, Scala 2.13 itself seems to be somewhat stricter on the cycles which are caused by using syntax imports within a library. I ran into that problem in spades with Matryoshka. Granted, some of that was just being generated by package objects, but still. It's an important warning, and I'm glad Dotty is stricter still on it.
This weekend I ran into a Dotty bug that turned up because of our use of
cats.syntax
methods incats.data
. The issues are easy enough to work around, but it's a good reminder that value classes are a mess and we might want to avoid extension methods in our own implementations.This PR replaces all use of
cats.syntax
extension methods incats/*.scala
andcats/data/*.scala
. Most of the replacements have a fairly neutral effect on readability, like usingIor.fromEither
instead of_.toIor
, oralgebra.remove(x, y)
instead ofx |-| y
, etc. In these cases we get to avoid some indirection and exposure to value class nonsense without bloating the code.In a few cases the non-syntax version is a significantly more verbose—in particular we use
bimap
onEither
a lot incats.data
. This is one case where the syntax method does have a non-trivial runtime cost. I've added a benchmark for two implementations ofmap
forEitherK
: the current one:…and one that doesn't use the
bimap
extension method:The non-syntax one gets 30% more throughput in this benchmark:
Given that the faster one is still arguably more readable, even if it's a little more verbose, I think avoiding
bimap
in our own implementations is reasonable.