Can we allow the syntax `v.[i]` to be converted to `getindex.(v, i)`?

Hi!

I have one scenario that happens all the time. I get a vector of vectors and I need to obtain each component individually to perform some analyses and plot the data. Today, I do:

``````getindex.(v, 1)
getindex.(v, 2)
getindex.(v, 3)
...
``````

However, I am wondering if we can allow the following syntax:

``````v.[1]
v.[2]
v.[3]
...
``````

It makes sense to me because we are broadcasting the get index operation.

What do you think?

3 Likes
3 Likes

Bear in mind this is different from OPâs intention to broadcast over the array as well:

``````julia> A = zeros(10,2);

julia> broadcast((idxs...)->A[idxs...], 1:10, 1) # ~getindex.((A,), 1:10, 1)
10-element Vector{Float64}:
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0

julia> getindex.(A, 1:10, 1)
ERROR: BoundsError
Stacktrace:
[1] getindex
@ ./number.jl:103 [inlined]
``````

If I had to pick, Iâd pick the former because itâs strange to think of a dotted instance as something that is iterated. I would prefer neither because itâs simpler to understand if we always dot the callable.

2 Likes

TLDR: there are three conflicting meanings to what `A.[I, J]` could possibly mean:

• You are implicitly assuming `A` is a collection of arrays and you want to perform the same indexing operation over all of them (this would be `getindex.(A, (I,), (J,))`)
• You are implicitly assuming `A` is a single array and you want to broadcast over the passed indices â great for fusing these accesses or doing âdiagonalâ indexing (this would be `getindex.((A,), I, J)`)
• Or you (probably donât) want both the array and the indices to participate in the broadcast simultaneously (this would be `getindex.(A, I, J)`)
4 Likes

I get it, but likeâŚ does anyone look at that and not expect the second one? I understand you could interpret other ways, but assuming `A` is an array of arrays in the first and last case seems IMO contrarian and not really the way most people would read that syntax. Maybe someone will say differently, but I havenât seen someone outside of that thread assume it would or could mean anything but `getindex.((A,), I, J)` like OP says. This is really a case of âperfect is the enemy of goodâ in my view.

3 Likes

If you apply the rule we apply for every other function it would be number 3 though.

2 Likes

Yes, both me and OP. I often miss a generalization of `first, last` that work for any index, and have often wanted exactly whatâs requested in OP.

Edit: after having read your post again, Iâm not quite sure which one youâre arguing for. In any case, I tend to miss the same functionality as OP.

7 Likes

should be this one right? then the others can be disambiguated like `Ref(A).[I, J]`, `A.[Ref(I), Ref(J)]`, etc.

3 Likes

That looks reasonable enough.

1 Like

An alternative would be to `stack` it into a matrix and then just use regular indexing:

``````u = stack(v)
u[1, :]
u[2, :]
...
``````
1 Like

Wrt developing multi indices access, as in `getindex.(Ref(x), is)`, further: also consider a more principled approach of GitHub - andyferris/Indexing.jl: Generalized indexing for Julia. There `Y = getindices(X, I)` always implies that `Y` has the same indices as `I` with values of `X`:

``````getindices(container, indices)

Return an indexable container with indices `keys(indices)` and values `container[i]` for
`i â values(indices)`. This generalizes scalar `getindex(container, index)` for multiple
indices, for dictionaries, tuples, named tuples, etc.
``````