-
-
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
Added collectFirst to Chain and NonEmptyChain #2796
Conversation
@LMnet thanks so much for contributing to Cats. cats/core/src/main/scala/cats/data/Chain.scala Lines 651 to 659 in 92fc8b3
Another thing that might be too much to ask: If we override collectFirst in Foldable, shall we also override collectFirstSome ?
|
…irst and collectFirstSome in the Foldable instances of Chain and NonEmptyChain.
@kailuowang Thanks for the fast review. I added |
* instead of `PartialFunction`s. | ||
*/ | ||
final def collectFirstSome[B](f: A => Option[B]): Option[B] = | ||
collectFirst(Function.unlift(f)) |
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.
Can we reimplement using foreachUntil
? The whole purpose of overriding the Foldable one is the performance gain, so I'd rather be sure that it reduces overhead to the minimum.
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.
I'm not 100% sure that this will give some noticeable performance improvement. I will try to benchmark this.
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.
Thanks I am curious to see the benchmark foreachUntil
implementation of collectFrist
v.s. the vanilla implementation from Foldable
using foldRight
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.
I finally find time for the benchmark.
I made a separate branch for benchmarking. Here is the commit with the code of the benchmark.
I removed overrides from the Foldable
instance to compare the performance of the default implementation of collectFirst
/collectFirstSome
from the Foldable
. Also, I added collectFirstSome2
with the specialized version of collectFirstSome
, based on foreachUntil
and without Function.unlift
.
I benchmarked small (size 5), medium (size 100) and large (size 1000000) chains.
I ran benchmarks with the following command: jmh:run -i 10 -wi 10 -f1 -t1 .*ChainCollectFirst.*
Benchmarks
Benchmark Mode Cnt Score Error Units
ChainCollectFirstBench.collectFirstSmallFoldable thrpt 10 7299195.442 ± 55930.435 ops/s
ChainCollectFirstBench.collectFirstSmallNew thrpt 10 19402233.046 ± 77203.919 ops/s
ChainCollectFirstBench.collectFirstMediumFoldable thrpt 10 349714.002 ± 1802.971 ops/s
ChainCollectFirstBench.collectFirstMediumNew thrpt 10 1065836.106 ± 11337.181 ops/s
ChainCollectFirstBench.collectFirstLargeFoldable thrpt 10 377742.008 ± 1213.396 ops/s
ChainCollectFirstBench.collectFirstLargeNew thrpt 10 1041808.061 ± 8960.744 ops/s
ChainCollectFirstBench.collectFirstSomeSmallFoldable thrpt 10 7260583.162 ± 66323.933 ops/s
ChainCollectFirstBench.collectFirstSomeSmallNew thrpt 10 15223500.005 ± 70156.918 ops/s
ChainCollectFirstBench.collectFirstSome2SmallNew thrpt 10 23795542.657 ± 53002.514 ops/s
ChainCollectFirstBench.collectFirstSomeMediumFoldable thrpt 10 376093.351 ± 2306.020 ops/s
ChainCollectFirstBench.collectFirstSomeMediumNew thrpt 10 1250584.212 ± 8875.084 ops/s
ChainCollectFirstBench.collectFirstSome2MediumNew thrpt 10 1412017.858 ± 13673.273 ops/s
ChainCollectFirstBench.collectFirstSomeLargeFoldable thrpt 10 392443.540 ± 2350.104 ops/s
ChainCollectFirstBench.collectFirstSomeLargeNew thrpt 10 1243549.960 ± 13598.336 ops/s
ChainCollectFirstBench.collectFirstSome2LargeNew thrpt 10 1399553.286 ± 7312.677 ops/s
*Foldable
is the default implementation fromFoldable
.*New
is new implementation from my PRcollectFirstSome2*New
iscollectFirstSome
based onforeachUntil
and withoutFunction.unlift
Results
- Implementations of
collectFirst
/collectFirstSome
from my PR is few times faster than defaults for anyChain
size. collectFirstSome
based oncollectFirst
andFunction.unlift
is ~2 times slower thancollectFirstSome
based onforeachUntil
for the small chains.collectFirstSome
based oncollectFirst
andFunction.unlift
has almost same performance ascollectFirstSome
based onforeachUntil
for the medium and large chains.
Conclusion
I changed collectFirstSome
implementation to foreachUntil
. I added a new commit to this PR.
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.
awesome! thanks so much for this contribution.
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.
Great PR, including benchmarks, really valuable! Thanks so much :)
Fixed #2795