All original content is created in Ukrainian. Not all content has been translated yet. Some posts may only be available in Ukrainian.Learn more

==, equal?, eql?, === in Ruby: what is checked and when to use

Post cover: ==, equal?, eql?, === in Ruby: what is checked and when to use
This content has been automatically translated from Ukrainian.
There are several ways to compare in Ruby. They are similar at first glance, but work completely differently.

== (values equality test)

  • Checks whether have objects with the same content.
  • Often redefined in classes (String, Array, Hash) to compare meaning rather than identity.
a = "hello"
b = "hello"

a == b # => true
a.equal?(b) # => false
== asks, "Are these objects of equal content?"

equal? (object identity verification)

  • Checks whether it's the same thing object in memory.
  • Not redefined in classes, always compares object id.
a = "hello"
b = "hello"
c = a

a.equal?(b) # => false
a.equal?(c) # => true
Here, to understand all this work, you need to know what an object is in Ruby.

eql? (strict equality check for hashes and numbers)

  • Checks value and type.
  • Mainly used in hashes for keys.
1 == 1.0 # => true
1.eql?(1.0) # => false, because different classes (Integer vs Float)
eql? more severe than ==.

=== (case-match operator)

  • It is used mainly in case construction (let's analyze it below).
  • Behaves differently for different classes:
    • In classes (String, Integer) - checks if an object belongs to the class (is_a?).
    • In regular expressions, checks whether the string falls under the pattern.
    • In Range - whether an object falls within a range.
case 5
when 1..10
  "In range" # => "In range"
end

String === "hello" # => true
/ell/ === "hello" # => true
Let's consider a case example in a little more detail. How does case ... when work in Ruby?
Syntax:
case object
when sample1
  code 1
when sample2
  code 2
else
  code_by_order
end
What happens under the hood
Ruby does something like this:
if sample1 === object
  code 1
elsif sample2 === object
  code 2
else
  code_by_order
end
That is when automatically uses === for comparison with case value. 
Examples for different types follow
Range (Range)
case 5
when 1..10
  "In range"
else
  "Out of range"
end
# => "In range"
Works like this, like Ruby executes (this is pseudo code):
(1..10) === 5 # => true
But it is important to note that normal use === on numbers or other types does not necessarily work the same way:
10 === (1..20) # => false
10 == (1..20) # => false
(1..20) == 10 # => false
Here Range#=== checks if a number is in the range.
Class
case "hello"
when String
  "That's a line"
when Integer
  "It's a number"
end
# => "This is a string"
Ruby performs:
String === "hello" # => true
Integer === "hello" # => false
For classes === — is the abbreviation for obj.is_a?(Class).
c) Regular expression
case "hello"
when /ell/
  "Coincidence with pattern"
else
  "No match"
end
# => "Coincidence with pattern"
Under the hood:
/ell/ === "hello" # => true
For Regexp, === checks if the string matches the pattern.
We moved a little off the subject === and moved on to case (because there === under the hood). Such a simple operator, but does different things.
To make it easier to remember:
  • case x; when y is not x == y, but y === x.
  • === works differently depending on the type of y:
    • Class -> is_a?
    • Range -> include?
    • Regexp -> =~ (line match)
This allows you to write conditions very flexibly.

This post doesn't have any additions from the author yet.

How self, protected and private (Ruby) works
28 Oct 13:52

How self, protected and private (Ruby) works

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Integer division in Ruby: why 6/4 is 1
28 Oct 14:10

Integer division in Ruby: why 6/4 is 1

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
28 Oct 14:42

How &:to_s works in Ruby and what Symbol#to_proc is

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
What are Proc and Lambda in Ruby?
28 Oct 15:57

What are Proc and Lambda in Ruby?

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
What happens if you call [1, 2, 3].map(&Person)
29 Oct 17:54

What happens if you call [1, 2, 3].map(&Person)

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Singleton class (eigenclass) in Ruby: what it is and why it is needed
29 Oct 18:29

Singleton class (eigenclass) in Ruby: what it is and why it is needed

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Include, Extend, Prepend in Ruby: how they work and what's the difference
29 Oct 21:20

Include, Extend, Prepend in Ruby: how they work and what's the difference

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
module_function in Ruby: When module methods are available as modular and as functions
29 Oct 21:53

module_function in Ruby: When module methods are available as modular and as functions

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
What is memoization in Ruby?
30 Oct 10:17

What is memoization in Ruby?

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
is_a?, kind_of?, instance_of? — how does Ruby check object type?
30 Oct 19:55

is_a?, kind_of?, instance_of? — how does Ruby check object type?

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
&& vs and — difference in Ruby that can break your code
30 Oct 20:23

&& vs and — difference in Ruby that can break your code

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
The variables in Ruby are @, @@ and class instance variable
30 Oct 20:54

The variables in Ruby are @, @@ and class instance variable

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska