Lazy subranges or `1:end` as entity


#1

Sometimes I’d like to be able to write

r = 1:End()-1
x[r] .= y[r]

Is this a good idea and how to achieve this?


#2

Are you concerned by the cost of building the 1:end - 1 range in:

x[1:end - 1] .= y[1:end - 1]

?


#3

No, not at all, just for readability in expressions like

sk=10; plot([first.(y[1:sk:end]) for y in ys[1:sk:end]],[last.(y[1:sk:end,end]) for y in ys[1:sk:end]])

vs

r=1:10:End()
plot([first.(y[r, end]) for y in ys[r]], [last.(y[r,end]) for y in ys[r]])

#4

You could define

  1. an End type, eg describing end + a,
  2. arithmetic on it,
  3. a Base.colon method, that emits another custom type which can contains ranges with this kind of endpoints,
  4. Base.getindex and Base.setindex method for this custom type.

I don’t think it is worth it though. If in the above example you don’t want End to resolve differently for x and y and they have the same indexes, you could use something like

r = indices(x, 1)[1:(end-1)]
x[r] .= y[r]

Otherwise, I think that x[1:(end-1)] .= y[1:(end-1)] is just more readable.


#5

I once (in Julia 0.2 or 0.3) made such an End type: https://bitbucket.org/maurow/ragged.jl/src/ebbd1cdfd796ef626e9c5193dc75b6494fe8b21f/src/Ragged.jl#lines-13
But I’m sure there are better ways to go about it. But it’s not trivial, that is why Julia opted for a syntax approach to the problem.


#6

I could also image to define something along the lines

struct Formula{T} f::T end
farg(args, symb) = last(args[findlast(x->first(x)==symb, args)])
import Base.getindex
(f::Formula)(;args...) = f.f(;args...)
getindex(a::AbstractArray, f::Formula) = a[f(END=length(a))]

so that for

r = Formula((;args...)->1:farg(args, :END)-1)
julia> rand(10)[r]
9-element Array{Float64,1}:
 0.355413 
 0.26395  
 0.260973 
 0.0454235
 0.860611 
 0.958574 
 0.912541 
 0.812007 
 0.500342 

and then define a macro @formula giving syntactic sugar to r = Formula((;args...)->1:farg(args, :END)-1)