juliaequalitycomposite-types

Equality testing of composite-type objects containing vectors doesn't work as expected. How to compare them?


I make a custom composite type (or structure), make two objects of that type, and test if they're equal:

struct mytype
    stuff::Int64
end

a = mytype(5)
b = mytype(5)

a == b
true

This works as I expected. However, if we make the contents a vector instead, comparing a and b returns false:

struct mytype2
    stuff::Vector{Int64}
end

a = mytype2([5])
b = mytype2([5])

a == b
false

a === b
false

isequal(a, b)
false

Any idea why this is? Is there a way to compare a and b in the second case, when they contain a vector?


Solution

  • The built-in (meaning you can't add methods) function === compares mutable structs by address and immutable structs by content. a === b is false because your immutable a and b contain two different arrays' addresses, so their contents are different. a.stuff === b.stuff is false because the arrays are separate with their own addresses.

    Then there is ==, a function that you CAN add methods to. By default, it falls back to ===, and the question "should == be recursive by default" is still an open issue for Julia v2 (4648). For now, it's expected that you write your own == methods for your own types. In fact, a.stuff == b.stuff is true because there are == methods specifically for Arrays of Numbers. So the simplest way for your type would be:

    Base.:(==)(a::mytype2, b::mytype2) = a.stuff == b.stuff
    

    In practice, your composite type probably has more fields so writing this stuff gets tedious. Issue 4648 includes a post (Jan 15 2021) of a generated function structEqual that does == on all fields of a struct, though I personally haven't tried it out.