Skip to content

Numeric#<=> returns nil unless the receiver is the argument - #3263

Merged
ksss merged 1 commit into
ruby:masterfrom
mmporong:numeric-cmp-nil
Oct 27, 2026
Merged

ksss merged 1 commit into
ruby:masterfrom
mmporong:numeric-cmp-nil

Conversation

@mmporong

Copy link
Copy Markdown
Contributor

Numeric#<=> returns 0 when the argument is the receiver itself and nil for anything else, as the RDoc comment above the signature says ("zero or nil"). The return type was Integer, which leaves out the nil case:

n = Numeric.new
n <=> n            # => 0
n <=> Numeric.new  # => nil
n <=> 1            # => nil

This changes the return type to Integer? and adds NumericInstanceTest#test_op_cmp for both results. With the current signature the new test fails on the nil case ("Call trace does not match one of method definitions"); with Integer? the Numeric tests pass, and so do the Integer, Float, Rational, Complex and Comparable tests (Ruby 4.0.9). rbs validate and rubocop pass.

The only values this implementation returns are 0 and nil, so 0? would also be accurate, like Kernel#<=> since #1945. This uses Integer? because the subclasses in core already do: Float#<=> and Complex#<=> return Integer?, and Integer#<=> / Rational#<=> return Integer? for an untyped argument. It also stays compatible with #3210, which discusses whether <=> that subclasses override should be typed as Integer?. It can be changed to 0? if that is preferred.

`Numeric#<=>` returns 0 when `other` is the receiver and nil otherwise,
as the comment above the signature says, but the return type was
`Integer`. Use `Integer?`, and add a test for both cases.
@ksss

ksss commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

I support your idea.
I think it is also correct from the perspective of LSP.
The "contract type" should be expressed rather than the "implementation type".

I also support #3210, but I did not mention it because it is in a draft state.
@apiology What do you think?

@ksss
ksss added this pull request to the merge queue Oct 27, 2026
Merged via the queue into ruby:master with commit 4215fc4 Oct 27, 2026
25 checks passed
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.

2 participants