In Ruby, what is the difference between == and ===? The RDoc says
Case Equality—For class Object,
effectively the same as calling #==,
but typically overridden by
descendents to provide meaningful
semantics in case statements.
#== the same as
==? And could you provide an example of when/how this is used in case statements?
The two really have nothing to do with each other. In particular,
#== is the equality operator and
#=== has absolutely nothing to with equality. Personally, I find it rather unfortunate that
#=== looks so similar to
#==, uses the equals sign and is often called the case equality operator, triple equals operator or threequals operator when it really has nothing to do with equality.
#=== the case subsumption operator (it’s the best I could come up with, I’m open to suggestions, especially from native English speakers).
The best way to describe
a === b is “if I have a drawer labeled
a, does it make sense to put
b in it?”
So, for example,
Module#=== tests whether
b.is_a?(a). If you have
Integer === 2, does it make sense to put
2 in a box labeled
Integer? Yes, it does. What about
Integer === 'hello'? Obviously not.
Another example is
Regexp#===. It tests for a match. Does it make sense to put
'hello' in a box labeled
/el+/? Yes, it does.
For collections such as ranges,
Range#=== is defined as a membership test: it makes sense to put an element in a box labeled with a collection if that element is in the collection.
So, that’s what
#=== does: it tests whether the argument can be subsumed under the receiver.
What does that have to with
case expressions? Simple:
case foo when bar baz end
is the same as
if bar === foo baz end
#== the docs mean “the instance method
== of the current object”.
=== is used in case statements as such:
case obj when x foo when y bar end
Is the same as
if x === obj foo elsif y === obj bar end
Some classes that define their own
=== are Range (to act like
include?), Class (to act like
Regexp (to act like
=~ except returning a boolean). Some classes that don’t define their own
=== are the numeric classes and String.
case x when 0 puts "Lots" when Numeric puts(100.0 / x) when /^\d+$/ puts(100.0 / x.to_f) default raise ArgumentError, "x is not a number or numeric string" end
is the same as
if 0 == x puts "Lots" elsif x.is_a? Numeric puts(100.0 / x) elsif x =~ /^\d+$/ puts(100.0 / x.to_f) else raise ArgumentError, "x is not a number or numeric string" end
=== is also used to match exceptions in
Here is an example
class Example def self.===(exception) puts "Triple equals has been called." true end end raise rescue Example # => prints "Triple equals has been called." # => no exception raised
This is used to match system errors.
SystemCallError.=== has been defined to return true when the two have the same errno. With this system call errors with the same error number, such as
Errno::EWOULDBLOCK, can both be rescued by listing just one of them.