Skip to content

Sort implicits with a proper comparison function #12562

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

Merged
merged 1 commit into from
May 22, 2021

Conversation

smarter
Copy link
Member

@smarter smarter commented May 21, 2021

Before this commit, we sorted implicits using prefer which relied on
compareOwner, but compareOwner does not induce a total ordering: just
because compareOwner(x, y) == 0 does not mean that compareOwner(x, z) and compareOwner(y, z) have the same sign, this violates the
contract of java.util.Comparator#compare and lead to an
IllegalArgumentException sometimes being thrown (although I wasn't able
to reproduce that, see #12479)

This commit fixes by this by replacing the usage of compareOwner by a
new compareBaseClassesLength which does induce a total ordering while
still hopefully approximating compareOwner well enough for our
purposes.

We also replace prefer which returned a Boolean by compareEligibles
which is directly usable as an Ordering we can pass to sorted, this is
more efficient than using sortWith(prefer) because the latter might end
up calling prefer twice for a single comparison.

Fixes #12479 (I hope).

@smarter
Copy link
Member Author

smarter commented May 21, 2021

test performance please

@dottybot
Copy link
Member

performance test scheduled: 1 job(s) in queue, 1 running.

@smarter smarter requested a review from odersky May 21, 2021 19:19
@smarter
Copy link
Member Author

smarter commented May 21, 2021

@odersky I ended up not adding a tie-break based on names like discussed in #12479 (comment) since that isn't actually necessary for a total ordering and so shouldn't matter here

@dottybot
Copy link
Member

Performance test finished successfully:

Visit https://dotty-bench.epfl.ch/12562/ to see the changes.

Benchmarks is based on merging with master (450f8ac)

@smarter smarter added this to the 3.0.1-RC1 milestone May 21, 2021
Copy link
Contributor

@odersky odersky left a comment

Choose a reason for hiding this comment

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

Otherwise LGTM

@odersky odersky assigned smarter and unassigned odersky May 22, 2021
Before this commit, we sorted implicits using `prefer` which relied on
`compareOwner`, but compareOwner does not induce a total ordering: just
because `compareOwner(x, y) == 0` does not mean that `compareOwner(x,
z)` and `compareOwner(y, z)` have the same sign, this violates the
contract of `java.util.Comparator#compare` and lead to an
IllegalArgumentException sometimes being thrown (although I wasn't able
to reproduce that, see scala#12479)

This commit fixes by this by replacing the usage of `compareOwner` by a
new `compareBaseClassesLength` which does induce a total ordering while
still hopefully approximating `compareOwner` well enough for our
purposes.

We also replace `prefer` which returned a Boolean by `compareEligibles`
which is directly usable as an Ordering we can pass to `sorted`, this is
more efficient than using `sortWith(prefer)` because the latter might end
up calling `prefer` twice for a single comparison.

Fixes scala#12479 (I hope).
@smarter smarter enabled auto-merge May 22, 2021 10:43
@smarter smarter merged commit 89e57aa into scala:master May 22, 2021
@smarter smarter deleted the implicit-sort branch May 22, 2021 11:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[implicit search] Comparison method violates its general contract!
3 participants