Any way to call `getindex(v, end)`?

If we have a vector v we can get the last element with v[end].
However that seems not to work with the equivalent getindex:

julia> v = rand(3);

julia> v[end]; # works

julia> getindex(v , end) #errors
ERROR: ParseError:
# Error @ REPL[37]:1:14
getindex(v , end) #errors
#            └ ── Expected `)`
Stacktrace:
 [1] top-level scope
   @ none:1

Anyway to get that going ?

The real use case is when using broadcasting with vector of vectors.
E.g. let’s say we want to get the last element from every vector

julia> vv = [rand(x) for x in rand(1:3, 3)]
3-element Vector{Vector{Float64}}:
 [0.37207620800228525, 0.8818089700283445, 0.39908834330666254]
 [0.35994314266508654]
 [0.38387950974422036, 0.2776285863311928, 0.403809461353824]

julia> getindex.(vv, length.(vv)) # currect working version
3-element Vector{Float64}:
 0.39908834330666254
 0.35994314266508654
 0.403809461353824

julia> getindex.(vv, end) # desirable that errors
ERROR: ParseError:
# Error @ REPL[40]:1:15
getindex.(vv, end) # desirable that errors
#             └ ── Expected `)`
Stacktrace:
 [1] top-level scope
   @ none:1

I would like to avoid length.(vv) and since I know that the infastructure for end is there, it seems like there should be some way to access it for such cases…

What about

last.(vv)

?

end in indexing expressions just lowers to lastindex. That is, v[end] is lowered to getindex(v, lastindex(v)):

julia> Meta.@lower v[end]
:($(Expr(:thunk, CodeInfo(
1 ─ %1 = v
│   %2 = v
│   %3 = Base.lastindex(%2)
│   %4 = Base.getindex(%1, %3)
└──      return %4
))))

What version of Julia are you on? In 1.10.2, the lowered code only evaluates the array expression once:

julia> Meta.@lower v[end]
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope`
1 ─ %1 = v
│   %2 = Base.lastindex(v)
│   %3 = Base.getindex(%1, %2)
└──      return %3
))))

which is obviously important for something like foo()[end] where computing the array does work (or worse, has side effects).

Hmm, looks like Julia master (1.12.0-DEV.360) replicates your results, though thankfully it only computes the array once if it’s more than a variable reference:

julia> Meta.@lower v[end]
:($(Expr(:thunk, CodeInfo(
1 ─ %1 = v
│   %2 = v
│   %3 = Base.lastindex(%2)
│   %4 = Base.getindex(%1, %3)
└──      return %4
))))

julia> Meta.@lower foo()[end]
:($(Expr(:thunk, CodeInfo(
1 ─ %1 = foo
│   %2 = (%1)()
│   %3 = Base.lastindex(%2)
│   %4 = Base.getindex(%2, %3)
└──      return %4

Not sure why it became more verbose in the v[end] case, but it looks harmless.

last returns the last batch of elements. For example, it would be even more complex to get the second to last element. Sukera’s lastindex is the exact equivalent.

I don’t think anyone has really answered this aspect of your question, but the answer is that end is a syntax keyword with exactly two uses: closing blocks (e.g., begin, if, etc) and this special case in [] ref expressions. You can’t even parse expressions that use end inside function calls like that, let alone “lower” them to their lastindex meaning.

julia> Meta.parse("getindex(A, end)")
ERROR: ParseError:
# Error @ none:1:13
getindex(A, end)
#           └ ── Expected `)`

This means it’s not even possible to make a macro that could do this transformation like @m getindex(A, end).

However, you could write a macro that goes in the other direction, transforming e.g. @bcast A[end] to getindex.(A, lastindex(A)), similar to @..

Or just use ibegin/iend from GitHub - JuliaArrays/EndpointRanges.jl: Julia package for doing arithmetic on endpoints in array indexing.