Equal Rights for Functional Objects – Henry Baker – Philip Potter - @philandstuff



Equal Rights for Functional Objects – Henry Baker – Philip Potter - @philandstuff

0 2


pwl-london-equal-rights

Papers we Love London Meetup #1: Equal Rights for Functional Objects

On Github philandstuff / pwl-london-equal-rights

Equal Rights for Functional Objects

Henry Baker

Philip Potter - @philandstuff

Table of Contents

introduction

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).

problem: many types of equality

Lisp EQ, EQL, EQUAL, EQUALP, STRING=, CHAR=… Smalltalk =, == Java ==, .equals() Perl ==, eq Python ==, is Ruby ==, eql?, equal?

oops

# Python
x = 1
y = 1
x is y
True
x = 500
y = 500
x is y
False

oops

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!

==, eql?, or equal?

# 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

lists

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"?

in java.util.List terms…

  • == is sometimes too fine
  • .equals() is sometimes too coarse

object identity

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

what do we really want from equality?

ONE equality operator!

equivalence relation

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

not too fine, not too coarse

solution: egal

Key idea is that of object identity:

Objects which behave the same should be the same.

Related to "identity of indiscernibles"

numbers

500 = 500

immutable lists

[1,2,3] = [1,2,3]

[a,b,c] = [a,b,c]

more generally, iterate over elements and recursively call egal

mutable lists

[1,2,3] = [1,2,3]?

mutable lists

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

in summary:

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)

implications

immutability matters

immutable views on mutable objects don't cut it

mutable lists & sets are rubbish

mutable objects should store a single value

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.

distributed systems

questions for discussion

reference equality isn't perfect for mutable objects

conflict: can't have reference equality and the ability to simulate other objects

laziness

;; clojure
(= (iterate inc 1) (iterate inc 1))
-- haskell
cycle [1] == cycle [1]

numeric conversions

does Integer 1 = Long 1?

does BigDecimal 1.0 = Long 1?

does BigDecimal 1.0 = BigDecimal 1.00?

what about functions?

functions are values too. can we compare functions? should we?

abstract data types & user-defined equality

internally mutable fields

for example: cached hashcode field as a performance optimization

remember this rule?

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)

fin

0