1

Is there any special Reason why the === and the == methods are implemented differently in the class Class?

"".class == String
#=> true

"".class === String
#=> false
Stefan
  • 109,145
  • 14
  • 143
  • 218
Eric
  • 163
  • 10
  • There's more fun: if you replace `String` with `""` in your example, you get opposite results :-) – Stefan May 12 '22 at 13:32

2 Answers2

2

The goal of === (called "case quality") is to be used within case statement. Creators decided that aliasing === with is_a? for Module instances works best with a common scenarios like:

def do_sth(object)
  case object
    when :nothing then ...
    when String then ...
    when Hash then ...
    else ...
end

=== should (almost) never be explicitly used outside of the case statement.

BroiSatse
  • 44,031
  • 8
  • 61
  • 86
2

We can further simplify your question I think. I believe you are asking is why

String == String # true

But

String === String # false

I think it's semi consistent by Ruby. the === equality asks if right side is a member of the left side.

So

Class === String

Is true since String is a member of Class. And indeed String is not a member of String.

What I do find weird though is that

5 === 5 # returns true

Imo it should return false to be consistent with String === String returning false, but for primitives Ruby has this quirk, probably so it works well with case statements.

Joel Blum
  • 7,750
  • 10
  • 41
  • 60
  • Further read on === and case statements: https://stackoverflow.com/a/3422349/1032663 – Joel Blum May 12 '22 at 11:31
  • It makes more sense when you think of it in terms of `case` statements: `when 1, 2, 3` matches the given values. `when 1..3, 5` matches everything within the range plus 5. `when ->(i) { i.odd? }` matches odd numbers. `when Integer` matches all integers. The "inconsistency" is actually pretty neat. – Stefan May 12 '22 at 11:57
  • Also note that `===` behaves that way because of the different receivers. There's [`Module#===`](https://ruby-doc.org/core-3.1.2/Module.html#3D-3D-3D-method), [`Range#===`](https://ruby-doc.org/core-3.1.2/Range.html#3D-3D-3D-method), [`Proc#===`](https://ruby-doc.org/core-3.1.2/Proc.html#3D-3D-3D-method) and more. Only the default [`Object#===`](https://ruby-doc.org/core-3.1.2/Object.html#3D-3D-3D-method) is equivalent to `==`. – Stefan May 12 '22 at 11:59