Suppose we have two types, A
and B
, which are just two wrapper types of Vector
s:
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 AbstractVector
s, 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 AbstractArray
s 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 SArray
s from StaticArrays.jl. Even though SArray
subtypes AbstractArray
, and setindex!
is required to be implemented for all AbstractArray
s, the purpose of SArray
s makes it fairly obvious that it shouldn’t have this method.
Thank you. If I do not subtype from AbstractArray
s, 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