This blog is part of our Ruby 2.4 series.

In Ruby, Object#equal? method is used to compare two objects by their identity, that is, the two objects are exactly the same or not. Ruby also has Object#eql? method which returns true if two objects have the same value.

For example:

str1 = "Sample string"
str2 = str1.dup

str1.eql?(str2)     #=> true

str1.equal?(str2)   #=> false

We can see that object ids of the objects are not same.

str1.object_id      #=> 70334175057920

str2.object_id      #=> 70334195702480

In ruby, Set does not allow duplicate items in its collection. To determine if two items are equal or not in a Set ruby uses Object#eql? and not Object#equal?.

So if we want to add two different objects with the same values in a set, that would not have been possible prior to Ruby 2.4 .

Ruby 2.3

require 'set'

set = Set.new           #=> #<Set: {}>

str1 = "Sample string"  #=> "Sample string"
str2 = str1.dup         #=> "Sample string"

set.add(str1)           #=> #<Set: {"Sample string"}>
set.add(str2)           #=> #<Set: {"Sample string"}>

But with the new Set#compare_by_identity method introduced in Ruby 2.4, sets can now compare its values using Object#equal? and check for the exact same objects.

Ruby 2.4

require 'set'

set = Set.new.compare_by_identity           #=> #<Set: {}>

str1 = "Sample string"                      #=> "Sample string"
str2 = str1.dup                             #=> "Sample string"

set.add(str1)                               #=> #<Set: {"Sample string"}>
set.add(str2)                               #=> #<Set: {"Sample string", "Sample string"}>

Set#compare_by_identity?

Ruby 2.4 also provides the compare_by_identity? method to know if the set will compare its elements by their identity.

require 'set'

set1= Set.new                          #=> #<Set: {}>
set2= Set.new.compare_by_identity      #=> #<Set: {}>

set1.compare_by_identity?              #=> false

set2.compare_by_identity?              #=> true