Indexing a number

If a number is generally treated as a list,

> 1[1]
1
> 1[2]
BoundsError
>length(1)
1

and so on, how come 1[:] gives an error?
I would have expected the result to be the same as [1][:].

I think this should be included for consistency.

The use case I have for this is that I import data that could be a number or a list. I use a function to import the data, and I have an optional index parameter:

function foo(filedata, index=:)
     return filedata[index]
end 

Without this feature I now have to make a special case for when filedata is a number.

that would imply you extracted a vector out of a scalar, which should be impossible.

julia> [1][:]
1-element Vector{Int64}:
 1

julia> [1][1:1]
1-element Vector{Int64}:
 1

julia> a = 1;

julia> a[1:1]
ERROR: MethodError: no method matching getindex(::Int64, ::UnitRange{Int64})
Closest candidates are:
1 Like

I agree that it is strange to extract a vector out of a scalar, but I still feel as though if
1[1] gives 1, then 1[1:1] should give the same result. It is no stranger to index a scalar in my opinion. I agree that it is strange, but for consistency I think 1[:] should be allowed.

1 Like

well, if you agree you shouldn’t be able to extract a vector out of a scalar, then it’s clear why 1[1:1] shouldn’t work.

Because [:] and [1:1] etc. always return a collection

3 Likes

Ahh, that makes sense. : always returns a collection. Thanks :slight_smile:

2 Likes

right; should have said that earlier, btw idk if this is true, but my mental model for Colon() is that:

a[:] === a[eachindex(a)]

and for a regular vector,

eachindex(a) == firstindex(a):lastindex(a) == 1:length(a)

I think the big breakthrough for me is more that 1:1 !== 1 but a collection from 1 to 1. I was just a bit lost in the nuance there. It’s easy to think that a[1] == a[1:1] is true for all a since it so often is the case. But it turns out that because indexing over scalars is (for some reason) allowed, it is not true. :man_shrugging:

2 Likes
julia> a = 1
1

julia> a[eachindex(a)[1]]
1

I’m just saying… If you can do eachindex(1) and it doesn’t throw an error… you shouldn’t have to add the extra [1] to make it work. :sweat_smile:

Maybe eachindex(a::Number) should just return 1 instead of Base.OneTo(1)? That would resolve the issue. Then I could use eachindex instead of :

(But yes, I see the arguments against, and I am no longer very upset that it doesn’t work like that. Only a little bit.)

Yeah, it’s the fact that the dimensionality of the indexed variable must match the sum of the dimensionality of the indices. This is also the reason why the first dimension is ‘dropped’ in M[1, :].

Not a list (that’s Python terminology), it’s there treated as an Array (though not really), and I found it surprising anyone (you) would try, but it seems intentional, since you can even treat as an n-dim Array (I suppose for (partial) support with MATLAB, that I thnk would even would allow 1[:], just because it’s possible and not too slow):

julia> 1[1, 1, 1]  # See with @edit 1[1, 1, 1]
1

getindex(x::Number) = x
function getindex(x::Number, i::Integer)
    @inline
    @boundscheck i == 1 || throw(BoundsError())
    x
end
function getindex(x::Number, I::Integer...)
    @inline
    @boundscheck all(isone, I) || throw(BoundsError())
    x
end

Since people went to the lengths of supporting this, I was curious couldn’t you just return a collection for e.g. 1[:]? A (regular) array, lives on the heap and is mutable, but a number can be on the stack, so a pointer to it (unless copied, and even then), wouldn’t be a good idea. That, and what is supported is slower, so why did YOU even try it?

It does seem to me that this should work since this does:

julia> fill(1)[1:1]
1-element Vector{Int64}:
 1

I took the liberty of filing an issue on GitHub: 1[1:1] should work · Issue #47166 · JuliaLang/julia · GitHub.

Should it? fill(1) creates a (0-dim) Array, and thus allocates (on the heap) as all Arrays, so that’a different story?

Heap allocation is an implementation detail, not sure why it should inform semantics.

Ok, I can understand that, and you might want to support more general. Maybe I’m blind to it, but is it really helpful to index a number? I thought you added it since easy in a non-allocating way, but adding more support reduces corner cases (and maybe allocations shouldn’t be to surprising).