# Custom index arithmetic

This is a clarifying question about custom indexing.

If `x::AbstractVector` has a conforming interface, can I assume that that the valid indexes are `firstindex(x):lastindex(x)`, ie they are

1. integers (so nothing wacky like `Float64`s or `Symbol`),
2. forming a contiguous range, so I can do arithmetic on them, at least `index += some_step`.

This is for an algorithm that I find difficult to express in an iterator form using `eachindex`.

Sorry if this is obvious and already clearly discussed in the manual.

1 Like

We currently assume that `axes(A::AbstractArray, i) <: AbstractUnitRange` in lots of code (so even tighter than your range assumption), and we also expect axes to have integer elements. I think youâ€™re safe to assume the same. A custom â€śarrayâ€ť that breaks this will already be in lots of deep water and Iâ€™d say theyâ€™re fine swimming out there on their own.

4 Likes

Thanks. Do you think it might be worth documenting this explicitly? I would then open an issue.

2 Likes

I also asked myself from time to time what should be assumed about `AbstractArray` indices. I guess its a common question, when writing generic code. So I think it would be good to document this.

2 Likes

After a close reading of the Interfaces and Arrays with custom indices documentation, I saw that both are pretty specific about `axes` returning (tuples of) `AbstractUnitRange`.

I am under the impression that this allows non-integer types though: anything goes that has a `oneunit`, eg I could define

``````struct RealUnitRange{T <: Real} <: AbstractUnitRange{T}
start::T
stop::T
len::Int
end

RealUnitRange(start, length::Integer) = RealUnitRange(start, start + length, length)

function Base.getindex(rur::RealUnitRange, i::Int)
@boundscheck @assert 1 â‰¤ i â‰¤ rur.len
rur.start + i
end

# ...
``````

and it would be valid for `axis` to return this. Or the same exercise with, for example, `Dates.Date`.

This means that I cannot rely on arithmetic with integers; I should at least increment with multiples of `oneunit`. Also, in theory, I could be worried about floating point error and similar, since the `eltype` of the range could be anything.

Is this a correct interpretation?

Interesting â€” you might be right. Itâ€™s not something that Iâ€™ve personally seen or tried, so I wouldnâ€™t be surprised if such an array would fail in some situations.

One thing we do assume is that `A[axes(A)â€¦] == A`. This means that it also needs to be a valid index type. We also sometimes grab axes from one array and use them to index into another â€” so it needs to be a valid index type for all array types. It may be possible to extend `to_index` to make that work for a non-integer, but Iâ€™d still be surprised if everything just worked.

Perhaps restricting to `AbstractUnitRange{<:Integer}` for the time being could be a reasonable limitation for the time being.

I think this is worth a clarification, so I will open an issue.