Lazy subranges or `1:end` as entity

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?

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

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

?

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]])

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.

2 Likes

I once (in Julia 0.2 or 0.3) made such an End type: Bitbucket
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.

1 Like

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)