nil and object identity
nil is an object too
nil is not the absence of a value; it is a value of class NilClass, and it answers methods. That is why a chain like x.nil? works even when x is missing, and why the error you get from nil.upcase is a NoMethodError rather than a syntax error.
ruby -e 'x = nil; puts x.nil?; puts x.inspect; p nil.to_a'
true
nil
[]
inspect prints nil for a reader, to_a gives an empty array, and to_s gives an empty string. A method that returns nil is not broken; it is saying "no value", and the caller decides what to do.
equal? is identity
Two strings with the same characters are equal values and two different objects. equal? asks whether two names point at one object, and it is almost never the method a program wants:
ruby -e 'puts "a".object_id == "a".object_id'
false
ruby -e 'a = "x"; b = "x"; puts a.equal?(b); puts a == b'
false
true
The two literals are separate objects with separate ids, which is why the first line prints false. A variable assignment copies the reference, so c = a; c.equal?(a) is true for any value, strings included.
== and eql?
== asks "same value" and is the one a program uses. eql? is the stricter form that a hash uses to find a key: it also compares the class.
ruby -e 'puts 1.eql?(1.0); puts 1 == 1.0'
false
true
So 1 and 1.0 are equal with == and different with eql?. A hash keyed by 1 does not find the value stored under 1.0, and a test that uses assert_equal passes for the pair because it uses ==.
- a.equal?(b) — one object, two names.
- a.eql?(b) — same class and same value; used by Hash and Set.
- a == b — same value; the method to define on your own class.
- a.hash — the number a hash table uses; define it whenever eql? changes.
What to watch for
Do not compare object ids. An id is unique for the life of an object and
is not stable across runs; a test that records one breaks on the next
run. Compare values with == and, when the type
matters, compare class as well.
A class that defines == should define
eql? and hash with it, or
two equal objects behave differently in an array and in a hash.
Next: Mutable, frozen and copied objects
Article author: Arthur Isaev