Identity and Equality
Part of the Object Oriented Programming section of Coddy's Ruby journey. Lesson 10 of 57.
A variable holds a reference to an object, not the object itself. Assigning it to another variable copies the reference, so both names then refer to the same object:
class Box
attr_accessor :count
def initialize
@count = 0
end
end
a = Box.new
b = a
b.count += 1
puts a.countOutput:
1equal? asks whether two references point to the same object, and object_id is each object's unique number. For your own classes, == does the same by default, so two objects with the same values are not equal:
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
end
a = Point.new(1, 2)
b = Point.new(1, 2)
c = a
puts a == b
puts a.equal?(b)
puts a.equal?(c)
puts a.object_id == c.object_idOutput:
false
false
true
trueDefine == to compare by value. include?, index and delete on arrays use ==, so they then find equal objects too. Check the class of other first, so comparing with a number or nil returns false instead of failing:
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def ==(other)
other.is_a?(Point) && x == other.x && y == other.y
end
end
a = Point.new(1, 2)
puts a == Point.new(1, 2)
puts a == 5
puts [Point.new(0, 0), Point.new(1, 2)].include?(a)
puts a.equal?(Point.new(1, 2))Output:
true
false
true
falsedup makes a new object with copies of the instance variables. Assigning a new value in the copy leaves the original alone, but an array or string inside is still shared between the two, because only the reference was copied:
class Team
attr_accessor :name, :players
def initialize(name)
@name = name
@players = []
end
end
a = Team.new("Reds")
b = a.dup
b.name = "Blues"
b.players << "Ada"
puts a.name
p a.playersOutput:
Reds
["Ada"]Challenge
EasyComplete the class Point so two points with the same coordinates are equal with ==, and comparing a point with anything else returns false. to_s returns (1, 2).
The supplied code reads points as x,y lines. For each point it prints (1, 2) same as first: true or false, then it keeps a list of distinct points using include? and finally prints distinct: 3 and whether the first point equals the text "1,2".
Your code goes in point.rb. main.rb holds the supplied input/output code and cannot be edited.
Try it yourself
require_relative 'point'
# Supplied input/output code: keep it as it is
input = []
while (line = gets)
input << line.chomp
end
points = input.map { |line| Point.new(*line.split(",").map(&:to_i)) }
points.each { |pt| puts "#{pt} same as first: #{pt == points[0]}" }
distinct = []
points.each { |pt| distinct << pt unless distinct.include?(pt) }
puts "distinct: #{distinct.size}"
puts "equals text: #{points[0] == input[0]}"
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Classes and Objects
Working With FilesDefining ClassesInstance VariablesMethods and selfto_s and inspectRecap - Library Card7Polymorphism and Duck Typing
PolymorphismDuck TypingAbstract Methodscase and ClassesRecap - Payment Methods2Accessors and Self
Readers and WritersCustom Settersself in MethodsIdentity and EqualityRecap - Contact List8Special Methods
Equality and hashOperator MethodsIndexing and AppendingCustom CollectionsRecap - Fractions11Project: Library Management
Books and MembersBorrowing Books3Class Methods and Variables
Class MethodsClass Instance VariablesConstantsFactory MethodsRecap - Coupon CodesPractice on your own: Online Ruby compiler