On Github philandstuff / pwl-london-equal-rights
The Joy of Clojure, Michael Fogus and Chris Houser
And if two objects aren't equal forever, then they're technically never equal (Baker 1993).
# Python x = 1 y = 1 x is y
True
x = 500 y = 500 x is y
False
public class Foo { public static void main(String[] args) { if (Integer.valueOf(200) == Integer.valueOf(200)) { System.out.println("Hooray!"); } else { System.out.println("Oh noes!"); } } }
Oh noes!
# ruby h1 = { "a" => 100, "b" => 200, :c => "c" } h1["a"]
100
h1 = { "a" => 100, "b" => 200, :c => "c" } h1.compare_by_identity h1["a"]
nil
if x = [1,2,3], and y = [1,2,3]:
are they equal?
are they the same?
can we answer this without resorting to "it depends"?
sugababes = Set.new [:mutya, :keisha, :siobhan]
sugababes.delete(:siobhan); sugababes.add(:heidi) # 2001
sugababes.delete(:mutya); sugababes.add(:amelle) # 2005
sugababes.delete(:keisha); sugababes.add(:jade) # 2009
new_band = Set.new [:mutya, :keisha, :siobhan] # 2011
reflexive:
a≡a
symmetric:
a≡b⟹b≡a
transitive:
a≡b∧b≡c⟹a≡c
Partitions the universe into equivalence classes
x≡y⟹f(x)≡f(y)
for arbitrary f
Key idea is that of object identity:
Objects which behave the same should be the same.
Related to "identity of indiscernibles"
500 = 500
[1,2,3] = [1,2,3]
[a,b,c] = [a,b,c]
more generally, iterate over elements and recursively call egal
[1,2,3] = [1,2,3]?
compare eq-cons on p3 of the paper
def same?(x,y) saved_head = x[0] x[0] = "My super-sekrit value" x[0] == y[0] ensure x[0] = saved_head end x = ["a"]; y = ["a"] puts "x=x: #{same?(x,x)}" puts "x=y: #{same?(x,y)}"
x=x: true x=y: false
compare simple values by value
compare mutable objects by reference
compare immutable objects by recursively comparing their components
(this is the one key idea of this paper)
immutable views on mutable objects don't cut it
It's too valuable to be able to compare lists and maps by value, that you want to use immutable values all the time. Rather than using a mutable list, use a mutable cell containing an immutable list.
conflict: can't have reference equality and the ability to simulate other objects
;; clojure (= (iterate inc 1) (iterate inc 1))
-- haskell cycle [1] == cycle [1]
does Integer 1 = Long 1?
does BigDecimal 1.0 = Long 1?
does BigDecimal 1.0 = BigDecimal 1.00?
functions are values too. can we compare functions? should we?
for example: cached hashcode field as a performance optimization
x≡y⟹f(x)≡f(y)
for arbitrary f
(= [1 2 3] '(1 2 3)) ;; true (conj [1 2 3] 4) ;; [1 2 3 4] (conj '(1 2 3) 4) ;; (4 1 2 3)