How to compare two vectors whose elements are equal but their types are not the same?

Suppose we have two types, A and B, which are just two wrapper types of Vectors:

struct A{T} <: AbstractVector{T}
   data::Vector{T}
end
struct B{T} <: AbstractVector{T}
   data::Vector{T}
end

Base.size(x::Union{A,B}) = (6,)

Base.getindex(x::Union{A,B}, i) = getindex(x.data, i)

And comparing two instances of them:

julia> x = collect(1:6);

julia> a = A(x)
6-element A{Int64}:
 1
 2
 3
 4
 5
 6

julia> b = B(x)
6-element B{Int64}:
 1
 2
 3
 4
 5
 6

julia> a == b
true

julia> a === b
false

But what I actually is that a == b is false since A and B are of different types. What should I do?

I’m not sure you should make them subtypes of AbstractVector. The equality behavior is inherited from it, and in many places we assume that AbstractVector is what it says it is: a vector object whose specific type rarely matters.

You could instead define abstract type PickyVector{T} end and make them subtypes of PickyVector, and then define generic operations on PickyVector.

3 Likes

Thank you for your answer. But I am defining them as vectors because I want to take advantage of the existing array interfaces and various methods. If I do not subtype them from AbstractVectors, I will have to write a lot of code by myself.

Can I just redefine == for A and B?

for op in (:(==), :isequal, :isapprox)
    @eval begin
        Base.$op(a::A, b::B) = false
        Base.$op(b::B, a::A) = false
    end
end

This obviously works to solve your short term problem. However, this will create an inconsistency with how we expect AbstractArrays to work, which can be detrimental to the overall user experience.

However, a) if these types are not exposed for anybody else to use, or b) if it’s clearly communicated that these are *not* fully-featured arrays, and proper expectations of their limitations and differences are set (and if those limitations are intuitive to users), then you should be ok.

I think a good example of this is setindex! for SArrays from StaticArrays.jl. Even though SArray subtypes AbstractArray, and setindex! is required to be implemented for all AbstractArrays, the purpose of SArrays makes it fairly obvious that it shouldn’t have this method.

Thank you. If I do not subtype from AbstractArrays, what specific interface can I implement? Is ArrayInterface.jl usable?

Augmenting Base functions with methods implementing different semantics is often a risky proposition. What you’re asking for is not how == is designed to be used. Many functions across Base and the larger package ecosystem depend on the existing semantics for correct operation.

Instead, I’ll suggest you consider implementing a new function for your purpose. Your objects can continue to behave across the ecosystem in all the ways you would expect, using the default ==. For example, this new function appears to implement what you’d like:

sametypeequal(x::T, y::T) where T = x == y
sametypeequal(x, y) = false

You can continue to use the array interface (with the default ==) and just call this function where you need these different semantics. If this is insufficient for your purposes (e.g., your objects don’t behave how you want with some other function that depends on ==), perhaps you can point out where those issues are and people can try to help.

2 Likes