Override the error message for avector[0]?

Proposal: override the error message for avector[0] with a message that specify explicitly that array indexing starts at 1 in Julia ??

I know: “If we do it for this, why not for …” but it is such a common error for people coming from C/Java/Python, that maybe it deserves a reflection (or maybe it has saready been discussed with a conclusion not to implement it, that’s fine…)

Does it?

3 Likes

well, we could append the error message with:

, the first index is $(firstindex(ary))

(special case 0 sounds okay, but most of the time it’s not useful because people won’t hard-code 0 over and over)

the language shouldn’t be optimized for first-time user and the goal is never to make Julia “you can use it without ever reading docs or googleing and just fix what error message says”

6 Likes

Without wanting to muddy the thread, these two cases’ error msgs are too similar for being so different:

julia> Int[1][0]
ERROR: BoundsError: attempt to access 1-element Vector{Int64} at index [0]

julia> Int[][0]
ERROR: BoundsError: attempt to access 0-element Vector{Int64} at index [0]
2 Likes

It seems like the problem is that the error reports the size of the array but given OffsetArrays etc, in order to understand bounds-checking failure you need to know the bounds, not the size, of the array.

1 Like

Something like this maybe

ERROR: BoundsError: attempt to access at index 0, valid indices are 1:231
22 Likes

That’s a nice, clear message. :+1:

3 Likes

I wonder if it’s more likely for them to know syntax 1:231 or that Julia is 1-based indexing.

In any case, we need to use firstindex() and lastindex() to generate that message in case OffsetArrays or similar is involved, but even then, some one may have a skipping-index array? (does this conflict with array interface?)

I would hope this would be a more general message than just "$(firstindex(x)):$(lastindex(x))" . Perhaps a showindices(io, x) that defaults to show(io, eachindex(x)) (perhaps with some cosmetic modification to things like Base.OneTo).

OffsetArrays already print something sensible:

julia> OffsetArray([1,2],3)[6]
ERROR: BoundsError: attempt to access 2-element OffsetArray(::Vector{Int64}, 4:5) with eltype Int64 with indices 4:5 at index [6]

julia> OffsetArray([1 2; 3 4],5,6)[6]
ERROR: BoundsError: attempt to access 2×2 Matrix{Int64} at index [6]

julia> OffsetArray([1 2; 3 4],5,6)[7,9]
ERROR: BoundsError: attempt to access 2×2 OffsetArray(::Matrix{Int64}, 6:7, 7:8) with eltype Int64 with indices 6:7×7:8 at index [7, 9]
4 Likes

As does StarWarsArrays:

julia> v = StarWarsArray(1:6, MacheteOrder)
5-element view(::UnitRange{Int64}, [3, 4, 1, 2, 5]) with eltype Int64:
 3
 4
 1
 2
 5

julia> v[1]
ERROR: StarWarsError: there is no episode 1 in MacheteOrder
11 Likes

I still like @gustaphe’s suggestion; we could do something like that for the default message in which case OffsetArrays may not even need to customize it. That said, it can be helpful to know the size and type of the array in figuring out which one errored… but that’s kinda secondary to the most important part (the attempted index and the valid indices).

It could also be helpful to more directly talk about what is wrong when there are the wrong number of indices for a multidimensional array or which dimension is the troublesome one.

3 Likes
showindices(io, x::MyRealIndexedObject) = print(io, "reals in [", lowerindex(x), ", ", upperindex(x), ")")
julia> x[1.25]
BoundsError: tried to access MyRealIndexedObject at index 1.25, legal indices are reals in [0.0, 1.0).

This might be overkill, but see what a bit of generality can do. Allowing some customization on this message would mean it’s more likely to be user friendly, rather than technically perfectly accurate.

3 Likes

What about Base.Experimental.register_error_hint? I know its experimental, but this could be readily used used to implement such hints:


Base.Experimental.register_error_hint(BoundsError) do io, ex
    arrayDim(::Array{T,N}) where {T,N} = N
    if ex.a isa Array && arrayDim(ex.a)>0 && 0 in ex.i
        printstyled(io,"\nHint: In Julia, the standart Arrays start at 1", color=:cyan)
    end
end

a=[1,2]
a[0]

BoundsError: attempt to access 2-element Vector{Int64} at index [0]
Hint: In Julia, the standart Arrays start at 1

Stacktrace:
.....

Unfortunately, it only takes the type as an argument, so it can’t tell you things like the maximum index for a specific instance.

1 Like

Yes it can! When a BoundsError is thrown, the errorhandler you defined for register_error_hint gets passed the thrown Exception (the argument ex in my example), and the Exception itself contains references to both the indices and the object (array) that was accessed (as ex.a for the array and ex.i for the indices, as a Tuple).

1 Like

Aw snap. Good you caught that before I finished my PR.