-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Let Array#sort only use <=>
, and let <=>
return nil
for partial comparability
#6611
Conversation
src/array.cr
Outdated
l.value = p.value | ||
l, p = p, p - 1 | ||
end | ||
l.value = v | ||
end | ||
end | ||
|
||
protected def self.cmp(v1, v2) | ||
v = v1 <=> v2 | ||
raise ArgumentError.new("comparison of #{v1} and #{v2} failed") if v.nil? |
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.
In exception messages title-case if preferred. Ditto below.
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 wish we hand't change that. This is how it looks right now:
Unhandled exception: Index out of bounds (IndexError)
from src/indexable.cr:596:8 in 'at'
from src/indexable.cr:73:5 in '[]'
from baz.cr:2:1 in '__crystal_main'
from src/crystal/main.cr:97:5 in 'main_user_code'
from src/crystal/main.cr:86:7 in 'main'
from src/crystal/main.cr:106:3 in 'main'
It doesn't look good to have an uppercase letter after :
. This is Ruby:
baz.cr:1:in `sort': comparison of Integer with 2 failed (ArgumentError)
from baz.cr:1:in `<main>'
I'll capitalize it, but I'd like to discuss reverting this capitalization.
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.
Fixed (rebased)
I'd suggest to add the explanation about the performance regarding |
@straight-shoota What do you suggest? Something like "You can return |
@straight-shoota With the above I don't mean to be rude, I just don't understand how we can recommend someone not to model their program correctly because it will perform worse. But I'm open to suggestions. |
1fe21d4
to
9b77b60
Compare
@straight-shoota Or, well, I could add "Note that if there is a chance that |
No offense taken. But I think it should be worth mentioning that there is a difference in performance depending on whether This was actually my most important concern when reading the PR (and your comments in #6608), how performance would play out for sorting completely comparable types vs. partially comparable types. And I think the implementation is really great. |
@straight-shoota Sounds good. Where should I add such comment? In |
I think I'd put it in |
999d37e
to
fa4e9d6
Compare
@straight-shoota Added the performance note. |
@asterite Could you rebase this? |
fa4e9d6
to
3d9737a
Compare
@straight-shoota Done! :-) |
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.
Yes, inlined is much better indeed 👍
@asterite Needs a rebase! |
… comparability. - Float <=> Float now will return `nil` for NaN - Removed PartialComparable
bd311e7
to
f01a0e9
Compare
Rebased! |
There was a recent PR that improved |
b07a102
to
0140f77
Compare
* 'master' of github.com:crystal-lang/crystal: Change the font-weight used in Playground (crystal-lang#7552) Fix formatting absolute paths (crystal-lang#7560) Refactor IO::Syscall as IO::Evented (crystal-lang#7505) YAML: fix test checking serialization of slices for libyaml 0.2.2 (crystal-lang#7555) Let Array#sort only use `<=>`, and let `<=>` return `nil` for partial comparability (crystal-lang#6611) Update `to_s` and `inspect` to have similar signatures accross the stdlib (crystal-lang#7528) Fix restriction of valid type vs free vars (crystal-lang#7536) Rewrite macro spec without executing a shell command (crystal-lang#6962) Suggest `next` when trying to break from captured block (crystal-lang#7406) Fix GenericClassType vs GenericClassInstanceType restrictions (crystal-lang#7537) Add human readable formatting for numbers (crystal-lang#6314) Add command and args to execvp error message (crystal-lang#7511) Implement Set#add? method (crystal-lang#7495)
Shouldn't the |
Yes, but it's a breaking change to do so, so we must be a bit careful. |
Unfortunately the |
Why don't we add a deprecation notice in the API docs for 0.28.0 and remove it in 0.29.0? |
We could flag the Maybe another check for deprecated methods is to detect overrides of abstract methods with |
Fixes #6608
This PR does a few things:
Array#sort
and related methods used to use<
and<=
instead of<=>
, as documented. This is fixed to only use<=>
.Comparable
andPartialComparable
into a single type.<=>
can now returnnil
, meaning that the two objects aren't comparable. This can be used when two objects of the same type can be compared, but not always (partial order). One such example are floats: they are usually comparable, except for NaN values.Array#sort
and related methods handle the case when<=>
returnnil
, and raise an exception in that caseNumber <=> Number
returnnil
for the case of NaN values, but provide an optimized implementation forInt <=> Int
that doesn't returnnil
I ran the benchmarks provided in the PR that introduced
intro
sort, but only checking forsort
andsort
with block, and compared them to the current implementation. The performance is the same, except when<=>
can returnnil
, in which the sorting is a bit less than 3 times slower. But that makes sense, because there's anil
check for every comparison now. I personally prefer to give a correct result than to silently fail at runtime. But this performance penalty only applies when<=>
returnsnil
, so it's not a very common case.The reason for removing
PartialComparable
and merging it withComparable
is that it's simpler to have just one module, and let it automatically indicate partial order ifnil
is returned. Ifnil
isn't returned, compiling with--release
should give the same performance, because the check fornil
will be optimized out.This PR also fixes the fact that even though we had
PartialComparable
, you couldn'tsort
such types (Array#sort
didn't handle the possibility ofnil
from<=>
).Note: I replaced an
Int32?
restriction withU forall U
to allow forsort
's block to be of typeInt32
orInt32?
, for performance reasons. Ideally we should be able to doU < Int32?
or some other condition over a free variable, but that's currently not supported. Eventually we can improve that code.