I have a struct which should behave like a matrix. I want to have all the standard indexing methods `julia`

has, like `A[:, j]`

, `A[1:3, j]`

, `A[[1,3,4], j]`

and so on.

Currently I have the following (simplified)

```
function Base.getindex(A::myMatrix, i::Int, j::Int)
#Doing some stuff
A(i, j)
end
```

Should I implement `Base.getindex(A::myMatrix, I::Vector, j::Int)`

and `Base.getindex(A::myMatrix, I::Range, j::Int)`

and the similar versions for `j`

?

Or is there a simple way to make the standard indexing available for a custom struct?

Thank you.

Check the section on the `AbstractArray`

interface. So long as `myMatrix <: AbstractArray`

(or in your case, likely `<: AbstractMatrix`

), the interface page tells you that you’ll get array/range indexing automatically. This will be implemented by looping over the scalar indexing you already defined.

If there are significant performance savings to be had from batching these multi-index accesses, you may consider implementing specialized methods for doing so. Exactly what to implement and for what input types is up to you and depends on the sort of savings you’re after.

If such batching efficiencies truly exist, I’d start with adding a `Base.getindex(A::myMatrix, i, j)`

method with untyped `i`

and `j`

and write it generically for that. You can continue to add increasingly specialized methods from there, until you decide there’s no longer significant benefit. In very few cases will the types of `i`

or `j`

need to be more specialized than `AbstractVector`

.

2 Likes

Thank you! I got the following

```
struct myMatrix <: AbstractMatrix{Float64}
# definitions
m::Int
n::Int
end
Base.size(M::myMatrix) = (M.m, M.n)
Base.getindex(M::myMatrix, i::Int, j::Int) = #some stuff
```

This seems to work. The manual mentions `Base.IndexStyle()`

. What is this for? Is necessary to implement this?

An `AbstractArray`

in Julia is allowed to have one of two preferred indexing schemes: Cartesian or Linear. `IndexLinear()`

is efficient when applicable and applies to normal Julia `Array`

types because of the way they’re stored in memory (the memory is snaked through the columns to form the array), but `IndexCartesian()`

is more general.

```
julia> collect(CartesianIndices(zeros(2,3)))
2×3 Matrix{CartesianIndex{2}}:
CartesianIndex(1, 1) CartesianIndex(1, 2) CartesianIndex(1, 3)
CartesianIndex(2, 1) CartesianIndex(2, 2) CartesianIndex(2, 3)
julia> collect(LinearIndices(zeros(2,3)))
2×3 Matrix{Int64}:
1 3 5
2 4 6
```

As you can see, the `LinearIndices`

of an array are of the form `a:b`

(but snake through the columns) while the `CartesianIndices`

represent each coordinate explicitly.

Julia tries to access arrays using their preferred mode (since one is usually more efficient than the other). `IndexCartesian()`

arrays implement `getindex(x,coordinate1,coordinate2,coordinate3...)`

while `IndexLinear()`

arrays implement `getindex(x,linearindex)`

. Julia will transform indexing operations to the preferred modality.

Since you wrote the method `Base.getindex(::myMatrix, ::Int, ::Int)`

, it sounds like you want `Base.IndexStyle(::Type{<:myMatrix}) = IndexCartesian()`

. The reason you didn’t have write this is that it’s the default.

1 Like

Thank you for such a detailed explanation! I learned a lot.