Search code examples
structjuliaequalsmutable

Struct equality with arrays


If I have arrays in a struct as below, I can't compare the equality of the struct because the arrays are mutable? Is there a way to get the equality to pass down to the array so that I get true for a([1,2,3]) == a([1,2,3])? Or is the only way to do this to extend Base.==?

julia> struct a
       v
       end

julia> a([1,2,3]) == a([1,2,3])
false

julia> a(1) == a(1)
true

julia> [1,2,3] == [1,2,3] # want the equality to work like this for the struct
true

julia> [1,2,3] === [1,2,3]
false

Solution

  • The answer by @miguel raz does not work at all!

    This happens since isequal is actually calling == rather than == calling isequal. In the isequal doc you can find explicitely that:

    The default implementation of isequal calls ==, so a type that does not involve floating-point values generally only needs to define ==

    Hence the correct code is:

    struct A
      v
    end
    import Base.==
    ==(x::A,y::A) = x.v==y.v
    

    However, a more elegant approach would be to write a generic code that does not rely on having the field v. Since we do not want to overload the default == operator we can define an abstract type that will tell Julia to use our implementation:

    abstract type Comparable end
    
    import Base.==
    
    function ==(a::T, b::T) where T <: Comparable
        f = fieldnames(T)
        getfield.(Ref(a),f) == getfield.(Ref(b),f)
    end
    

    Now you can define your own structures that will correctly compare:

    struct B <: Comparable
        x
        y
    end
    

    Testing:

    julia> b1 = B([1,2],[B(7,[1])]);
    
    julia> b2 = B([1,2],[B(7,[1])])
    
    julia> b1 == b2
    true