Project

General

Profile

Actions

Bug #18937

closed

Inconsistent definitions of Complex#<=> and Numeric#<=> with others

Added by msnm (Masahiro Nomoto) almost 2 years ago. Updated over 1 year ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:109311]

Description

Object#<=> says "Returns 0 if obj and other are the same object or obj == other" .
https://ruby-doc.org/core-3.1.2/Object.html#method-i-3C-3D-3E

However, neither Complex#<=> nor Numeric#<=> satisfies that definition.

num1 = Complex(0, 42)
num2 = Complex(0, 42)
p num1.equal?(num2)  #=> false
p num1 == num2       #=> true

# using Complex#<=>
p num1 <=> num2  #=> nil

# using Numeric#<=>
Complex.remove_method(:<=>)
p num1 <=> num2  #=> nil

# using Object#<=> (Kernel#<=>)
Numeric.remove_method(:<=>)
p num1 <=> num2  #=> 0

Complex#<=> has another problem that it does not coerce numeric objects while Integer#<=> and Float#<=> do.
This prevents users from adding yet another complex class having #<=>.


Here is my proposal of Complex#<=> behavior (in Ruby).
This considers #15857, complex numbers are comparable when their imaginary parts are 0.

class Complex
  def <=>(other)
    return (self == other ? 0 : nil) if self.imag != 0

    if other.kind_of?(Complex)
      if other.imag == 0
        return self.real <=> other.real
      else
        return nil
      end
    elsif other.kind_of?(Numeric) && other.real?
      return self.real <=> other
    elsif other.respond_to?(:coerce)
      num1, num2 = other.coerce(self)
      return num1 <=> num2
    else
      return nil
    end
  end
end
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0