deepcopy, which recursively copies the object down to its “atoms”. Has anyone written the corresponding
deepequal, such that
deepequal(deepcopy(x), deepcopy(x)) == true?
Under what circumstance would
deepequal yield different results to
deepcopy, presumably you would want to change some component and not affect the object you copied from.
But I can’t think of a reason why you would need a
Whenever you want to know that two structures are equivalent?
julia> isequal(Ref(1), Ref(1)) false
That would be
I think it’s a bit like
deepcopy. Not super clean semantically, but can be very useful for testing/debugging/rapid development.
FWIW, there’s a classic Lisp article on why multiple
copy / equality implementations are needed: https://www.nhplace.com/kent/PS/EQUAL.html
Not that I know of. FWIW, I think that generally
isequal should be used by most user code, and types should just define the relevant methods.
That said, I often define custom equality operators (eg for unit testing), it is pretty easy to do recursively. Cf
struct, use in a generated function.
There doesn’t exist one, but you can easily define your own if you really need it. The following function is one I’ve found useful in the past to extend
== for my own types:
function deepequal(a, b) typeof(a) == typeof(b) || return false N = fieldcount(typeof(a)) for i in 1:N getfield(a, i) == getfield(b, i) || return false end return true end
I also just cooked up the following which is more generic, but haven’t tested it very thoroughly, and really don’t know if it’s really worth it to write as a
@generated function deepequal(a, b) # check the types a == b || return :(false) N = fieldcount(a) # fallback to regular comparison for primitive types N == 0 && return :(a == b) # unroll the loop, because it's cool! quote Base.@nexprs $N i -> (getfield(a, i) == getfield(b, i) || return false) return true end end
edit: actually, for what you want both functions should be recursive. The comparisons should be
deepequal(getfield(a, i), getfield(b, i)) rather than
Thanks! I thought of writing my own, but the deepcopy internals are surprisingly complex. Eg. Your
deepequal would fail with circular structures, and it might fail with arrays/dicts. I was hoping someone had provided it in a package or something.
Ref(1) == Ref(1) falls back to
=== by default. You can check this with
julia> @edit Ref(1) == Ref(1). Most regular containers check their content already (e.g.
 == ), so if you define
== on your type to check its own fields as well, it should work out fine. Just make sure to special case circular dependencies or disallow your type to contain itself.