-
Notifications
You must be signed in to change notification settings - Fork 326
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
Merge ordered and unordered comparators #5845
Conversation
aae0541
to
cae98e6
Compare
Benchmarks improved - |
distribution/lib/Standard/Base/0.0.0-dev/src/Data/Ordering.enso
Outdated
Show resolved
Hide resolved
distribution/lib/Standard/Base/0.0.0-dev/src/Data/Ordering.enso
Outdated
Show resolved
Hide resolved
distribution/lib/Standard/Base/0.0.0-dev/src/Data/Ordering.enso
Outdated
Show resolved
Hide resolved
That rapidly decreased performance - #5709 (comment)
# Conflicts: # CHANGELOG.md # distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json.enso # test/Table_Tests/src/Common_Table_Operations/Join/Join_Spec.enso # test/Tests/src/Data/Ordering_Spec.enso # test/Tests/src/Data/Text_Spec.enso # test/Tests/src/Data/Time/Duration_Spec.enso
case Meta.is_same_object eq_self Default_Comparator of | ||
True -> | ||
case eq_self.is_ordered of | ||
True -> | ||
res = eq_self.compare self that | ||
case res of | ||
Ordering.Equal -> True | ||
_ -> False | ||
False -> | ||
res = eq_self.equals self that | ||
case res of | ||
Nothing -> False | ||
_ -> res | ||
# Comparable.equals_builtin can return Nothing when self and that | ||
# are incomparable. | ||
case Comparable.equals_builtin self that of | ||
True -> True | ||
_ -> 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.
minor nitpick but I'm a bit surprised we do the case-of
check instead of just delegating to Default_Comparator.compare
which could be the place that will then call Comparable.equals_builtin self that
?
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.
Default_Comparator.compare x y
has to handle three cases - x==y
, x<y
or x>y
- which is implemented with three nested case expressions. If x
and y
are neither, i.e., are not equal, all of these three cases have to be evaluated. So this is, once again, because of the performance - it is just a shortcut.
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.
OK.
I'm really surprised we have these 3 builtins. IMO one builtin compare x y
returning -1, 0, +1 or null
could work just as well or maybe even better.
Like, if you are comparing two Text values that have 1M characters of length (an exaggerated example but well...), assume the difference is at second to last character. The equals check will have to iterate the whole string and find the diff at the end, to determine they are not equal. But are they greater or smaller? Now we have to iterate the whole string once again...
Instead with compare
approach we'd do this at one time.
I think even for integers/floats the JVM should be able to boil down a == + < into a single three-way compare instruction (although [citation needed]).
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.
We don't have 3 builtins for comparisons, we have only 2 - EqualsNode
(Comparable.equals_builtin
) and LessThanNode
(Comparable.less_than_builtin
). Merging their functionality into one is inappropriate because many types that can be compared with ==
, cannot be compared with <
- Just compare the number of specializations we have in EqualsNode
and compare it to the number of specializations in LessThanNode
. Moreover, LessThanNode
now has a different return value, as it can return Nothing
for values that are incomparable.
The example with a string with 1M characters is, indeed, exaggerated. Besides, merging EqualsNode
and LessThanNode
in one single node might bring us some performance improvement. But comparing it to other low hanging fruits, like problems with nested case expressions, it would be negligible.
distribution/lib/Standard/Base/0.0.0-dev/src/Data/Ordering.enso
Outdated
Show resolved
Hide resolved
distribution/lib/Standard/Base/0.0.0-dev/src/Data/Ordering.enso
Outdated
Show resolved
Hide resolved
distribution/lib/Standard/Base/0.0.0-dev/src/Data/Ordering.enso
Outdated
Show resolved
Hide resolved
distribution/lib/Standard/Base/0.0.0-dev/src/Data/Ordering.enso
Outdated
Show resolved
Hide resolved
engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java
Outdated
Show resolved
Hide resolved
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.
Looks good.
I will appreciate updating the docs along the lines of what was suggested. Especially the incomparable/partial-ordering concept is a bit subtle, let's try to explain it carefully. Remembering that we used to have ordered/unordered comparators where all elements behaved in one way or another. Now we have partial-orderings by default so we can have mixed behaviour, depending on what pair of values of a given type is compared.
d0c8778
to
635f1c9
Compare
Pull Request Description
Merge ordered and unordered comparators into a single one.
Important Notes
Comparator is now required to have only
compare
method:Checklist
Please include the following checklist in your PR:
Scala,
Java,
and
Rust
style guides.
./run ide build
and./run ide watch
.