## A Useful Julia Macro To Define Equality And Hash

From: andrew cooke <andrew@...>

Date: Fri, 5 Jun 2015 22:04:34 -0300

Julia has two kinds of composite types - immutable and mutable.

Immutable is more like a "value" type.  Instances are copied, and equality and
hash, by default, are based on the "bit pattern" contained.

In contrast, mutable is more like "a pointer to a struct".  Instances are
passed by reference, and equality and hash are based on the address.

If an immutable type includes a field that is a mutable type then equality

So for all mutable types, and for many immutable types, it is important to
define equality and hash functions that iterate over the contents.

Typically you write code like:

type Foo
a::Int
b
end
hash(x::Foo) = hash(x.a, hash(x.b))
==(x::Foo, y::Foo) = x.a == y.a && x.b == y.b

Which gets tiring after a time.  Hence this macr which generates the above
from

@auto type Foo
a::Int
b
end

Disclaimer: this is freshly written, hardly tested, and I am no Julia guru!

Andrew

import Base.hash

function auto_hash(name, names)

function expand(i)
if i == length(names)
:(hash(a.$(names[i]))) else :(hash(a.$(names[i]), $(expand(i+1)))) end end quote function hash(a::$(name))
$(expand(1)) end end end function auto_equals(name, names) function expand(i) if i == length(names) :(a.$(names[i]) == b.$(names[i])) else :(a.$(names[i]) == b.$(names[i]) &&$(expand(i+1)))
end
end

quote
function ==(a::$(name), b::$(name))
$(expand(1)) end end end macro auto(typ) @assert typ.head == :type name = typ.args[2] @assert typeof(name) == Symbol fields = typ.args[3].args names = Array(Symbol,0) for i in 1:length(fields) if typeof(fields[i]) == Symbol push!(names, fields[i]) elseif typeof(fields[i]) == Expr && fields[i].head == :(::) push!(names, fields[i].args[1]) end end quote$typ
$(esc(auto_hash(name, names)))$(esc(auto_equals(name, names)))
end
end

### Fixed Version

From: andrew cooke <andrew@...>

Date: Sat, 6 Jun 2015 07:37:03 -0300

The code above needs \$(esc(typ)) near the end and better unpacking of the name
of a tyope when it is a subclass.

Code used "for real" is available at
https://github.com/andrewcooke/ParserCombinator.jl/blob/master/src/auto.jl

Andrew