-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Optimised implementation of List.filter/filterNot #5653
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
Conversation
I agree that this kind of strategy seems like it should be an optimization, but have you tested with microbenchmarking? The concern is that it's pretty complicated code, and that sometimes can result in less effective optimization and thus worse performance for the majority of cases. |
@Ichoran I have, I need to tidy up the my benchmark code and share it - for this kind of work I agree that we need to demonstrate the performance/complexity tradeoff. |
Well, I won't make the same comment on every PR, but I am thinking the same thing on each one, so maybe you can update them all. |
@@ -405,6 +405,90 @@ sealed abstract class List[+A] extends AbstractSeq[A] | |||
// Create a proxy for Java serialization that allows us to avoid mutation | |||
// during de-serialization. This is the Serialization Proxy Pattern. | |||
protected final def writeReplace(): AnyRef = new List.SerializationProxy(this) | |||
|
|||
override def filter(p: A => Boolean): List[A] = filterImpl(p, isFlipped = false) |
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.
Mima has the last word. Apparently, return type should be TraversableLike.this.Self
.
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 @som-snytt - will sort this out over the weekend.
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.
@som-snytt My type foo is not strong enough - I can't work out what the correct type signature here looks like - any hints greatly appreciated
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.
Me neither, apparently it makes no diff. Sorry about that. The current filter is on AbstractTraversable. You always get both sigs, returning Object and List, when you define it on List, because that's what Self is.
@rorygraves My benchmark linked and described over in #5650 (comment) might serve as an example for your benchmark for this PR. |
@retronym Thanks - will add one over the weekend. |
389a532
to
73222c7
Compare
@retronym I've added a benchmark - I will run it on a stable machine this evening and post the results. |
I don't think there is a correct type signature that would make this work in a forward binary compatible way. The old version gets
The new version with the overrides has:
The return type is statically known to be |
Here's a mindless refactor to a trait: where then
|
Thanks @som-snytt (and @szeiger ) I will look at this in a couple of hours. |
73222c7
to
e12844f
Compare
@som-snytt Thats for your input and suggestions - hopefully this will pass MIMA. Below are the benchmarks for the attached changes. With changes
Before changes:
|
BTW, if the primary goal here is compiler performance, and you've identified a hot path using |
@retronym The compiler performance was definitely the target - it seemed nice to fix the generic performance whilst I was there. I will look at moving it to collections - thanks |
@som-snytt Nice trick. I hadn't considered moving the overrides to a separate trait. |
Unfortunately it means hat he basic list performance does not improve. I guess this will always break MIMA does that mean the change as is could never go in (until 2.13) might be moot if 2.13 rewrites all he collections anyway. |
It's still a worthwhile change for 2.13.x. We're changing the design of the collections library but we will rely heavily on the existing implementations, so any change that adds a more efficient implementation of a collection method for a specific collection type is useful. |
@rorygraves Did you run benchmarks for the new binary compatible version? Is it slower than the original one? |
The updated ones are similar to the above, but MIMA still fails after the change. I updated my gist which I can't post right now |
Oh, right, it still fails. I didn't pay attention to the fact that this is the 2.11.x branch where we don't run all tests and accumulate the errors. The errors are different though:
These are caused by I'm not sure whether we should accept such a change. It is forward binary compatible for any Scala code compiled against the newer version but not for Java code (which could exploit the fact that |
Let's change the name so it ends in 'Internal'. If no one else objects, I'm fine whitelisting it then. |
@adriaanm That I can do :) |
e12844f
to
0ec7228
Compare
0ec7228
to
c03811b
Compare
@adriaanm Updated trait name as suggested - have not updated MIMA rules as I was unsure how to do that. |
This morning I looked at the actual test failures. One is just an update due to List's parents. But maybe the symbol forcing test means something substantial? It looks like something happens out of order with the change. The test uses scope.sorted.filter but I didn't dig deep. (Because it's a work day.) |
The change is in the ordering of
in
It looks like the change is simply due to the changed order of declaration. In fact, merely adding these overrides to
without |
I'm preparing a PR to consolidate the three PRs currently open and address the remaining bureaucratic mima/test issues ;-) (See #5664) |
Commits moved to #5664. Thanks! |
No description provided.