Base operator on custom array

Here I define a struct


struct Df{T,N} <: AbstractArray{T,N}
    value::AbstractArray{T,N}
end

Base.size(df::Df)=size(df.value)

Base.getindex(df::Df,i...)=Df(df.value[i...])
Base.getindex(df::Df,i::Union{Int,CartesianIndex}...)=df.value[i...]
Base.eachindex(df::Df)=eachindex(df.value)

-> df=Df([[1,2,3] [2,3,4]])

3×2 Df{Int64, 2}:
 1  2
 2  3
 3  4

Then, I can apply Base operator ( like + - ) on df

-> df .+ 1

3×2 Matrix{Int64}:
 2  3
 3  4
 4  5

But the result is a Matrix rather than a Df. The expected result would like:

-> df  .+ 1

3×2 Df{Int64, 2}:
 2  3
 3  4
 4  5

What am I missing here?

You need to define a few methods for broadcasting. The example at the end of Interfaces · The Julia Language is ver close to what you want.

1 Like

You’ll also need to implement the broadcasting API to preserve the matrix type: Interfaces · The Julia Language

Edit: what @skleinbo said :slight_smile:

1 Like

Abstract field types are very bad for performance. It’s normally better to either just wrap Array{T, N} or make the wrapped array type a type parameter for Df.

1 Like

Thanks for your advice. I have changed it to this:

struct Df{K,T,N,D,C} <: AbstractArray{T,N}
    index::Vector{K}
    value::C
    column::D
    Df{K,T,N,D,C}(index::Vector{K},value::AbstractArray{T,N},column::D=nothing) where {K,T,N,D,C}=
            new{K,T,N,D,C}(index,value,column)
end

Would it be better, right?

Yes, the example is very close. Thanks very much for your help.