# \`view\` and \`\[ \]\` with "slice object"

**URL:** <https://discourse.julialang.org/t/view-and-with-slice-object/102285>\
**Category:** General Usage\
**Created:** [July 31, 2023, 4:06am UTC](https://discourse.julialang.org/t/view-and-with-slice-object/102285 "2023-07-31T04:06:35Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [July 31, 2023, 4:06am UTC](https://discourse.julialang.org/t/view-and-with-slice-object/102285/1 "2023-07-31T04:06:35Z")

</div>

A tuple is often used to encapsulate a set of array sizes: `sz = size(multi_dim_arr)` and use `sz` later. In a similar manner, I sometimes want to encapsulate an array “slice” in an object, but I’m wondering what’s the best way.

```julia
arr = rand(Float64, 3, 5)
s = size(arr) # -> Tuple (3,5)
b = fill("hello", s) # works
b = fill("hello", 3, 5) # works, too.
slice = ( :, 2)
c = view(arr, slice) # error
c = view(arr, slice...) # works
d = arr[slice...] # works, too.
slice2 = CartesianIndices((:, 2)) # error
slice2 = CartesianIndices((1:3, 2)) # fine
e = arr[slice2] # works

```

As you can see, there isn’t quite a “slice object” that can express a general slice. `CartesianIndices` comes close but it can’t include a `Colon`-only range.

It would be nice if `view` and `[]` accepted a slice object that can be used like

```julia
function func(sl2d)
   # build a 4D array
   t = view(arr4d, sl2d)
   u = arr[sl2d]
   func_on_2d_arr(t) # or u
end
sl = Slice(4, :, 3, 2:9)
func(sl)

```

So, my question is whether there is an idiomatic way to encapsulate a slice in a variable (object) and use it later. Is `v[tuple...]` the way to go? Or would it make sense to extend `view` and `[]` to take a slice object (as represented by a tuple, for example)?

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [July 31, 2023, 3:49pm UTC](https://discourse.julialang.org/t/view-and-with-slice-object/102285/2 "2023-07-31T15:49:49Z")

</div>

It seems that your proposed `Slice` object is a reasonable way to do this (although be careful to avoid mixing it up with `Base.Slices`).

An extremely simple implementation might look like this

```julia
struct ArraySlice{T<:Tuple}
	s::T
end

ArraySlice(s...) = ArraySlice(s) # Vararg constructor

Base.getindex(x::AbstractArray, slice::ArraySlice) = Base.getindex(x, slice.s...)
Base.view(x::AbstractArray, slice::ArraySlice) = Base.view(x, slice.s...)

```

It’s important that a specialized object was used for this (which you appear to suggest already, but I’m emphasizing it here). Do not simply overload `Base.getindex(x::AbstractArray, slice::Tuple)` so that tuples are interpreted like your slice object. That would be type piracy and would have the potential to break things spectacularly if some other code (that you write or load, or that something you load loads) were to try a similar overload.

* * *

Another option, if you have the object (or its indices) known to you in advance so that you can resolve `:`, `begin`, and `end` immediately, is to slice the `CartesianIndices` of your target object

```julia
julia> a = zeros(2,3,4);

julia> sl = CartesianIndices(a)[:,3:-1:1,4]
2×3 Matrix{CartesianIndex{3}}:
 CartesianIndex(1, 3, 4) CartesianIndex(1, 2, 4) CartesianIndex(1, 1, 4)
 CartesianIndex(2, 3, 4) CartesianIndex(2, 2, 4) CartesianIndex(2, 1, 4)

julia> sl = @view CartesianIndices(a)[:,3:-1:1,4]
2×3 view(::CartesianIndices{3, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}, Base.OneTo{Int64}}}, :, 3:-1:1, 4) with eltype CartesianIndex{3}:
 CartesianIndex(1, 3, 4) CartesianIndex(1, 2, 4) CartesianIndex(1, 1, 4)
 CartesianIndex(2, 3, 4) CartesianIndex(2, 2, 4) CartesianIndex(2, 1, 4)

```

Note that the `getindex` version of this is producing an `Array` (`Matrix`, in this case), which will allocate. The `view` version should not, so is probably preferable. Note that you don’t need to pass `a`, but can instead use `CartesianIndices(axes(a))` if you only know the `axes` of your target. You can even go so far as to just use the `size`, although that is fragile because it may break for `OffsetArrays` or other non-1-indexed arrays.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [July 31, 2023, 4:12pm UTC](https://discourse.julialang.org/t/view-and-with-slice-object/102285/3 "2023-07-31T16:12:44Z")

</div>

Colons (and other unusual indexing things) get converted upon indexing/view using [`to_indices`](https://docs.julialang.org/en/v1/base/arrays/#Base.to_indices). CartesianIndices don’t support `:` because they don’t have the context about the array they’ll eventually be used in. You can give them that context:

```julia
julia> arr = rand(Float64, 3, 5);

julia> slice = ( :, 2)
(Colon(), 2)

julia> slice2 = CartesianIndices(to_indices(arr, slice))
CartesianIndices((1:3, 2))

```

Overloading indexing like @mikmoore suggests is going to be a huge headache of ambiguities, I would think. You could overload `to_indices(arr, inds, S::ArraySlice)` if you wanted to index with such an object without splatting. But I’d just splat the tuple.

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [August 2, 2023, 3:49am UTC](https://discourse.julialang.org/t/view-and-with-slice-object/102285/4 "2023-08-02T03:49:17Z")

</div>

Thank you folks for your detailed, well-informed discussion! I now know how or in which way I should proceed.

In the meanwhile, as I write small programs, I find myself wanting to write

```julia
slice = (1:10:end) # strided indexing
. . .
func(v[slice], . . .)
another_func(arr[slice], . . .)

```

which doesn’t work because `end` isn’t known in that context.

Writing in Fortran, I used to have a lot of little branches. In Julia, most of such branches are gone because you can encapsulate various information in variables (objects). Array slicing is probably the last thing (to me) for which there is no idiomatic or obvious solution.

---

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [August 2, 2023, 4:21am UTC](https://discourse.julialang.org/t/view-and-with-slice-object/102285/5 "2023-08-02T04:21:22Z")

</div>

Perhaps [GitHub - JuliaArrays/EndpointRanges.jl: Julia package for doing arithmetic on endpoints in array indexing](https://github.com/JuliaArrays/EndpointRanges.jl) might help with this?

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [August 8, 2023, 1:01am UTC](https://discourse.julialang.org/t/view-and-with-slice-object/102285/6 "2023-08-08T01:01:11Z")

</div>

> [@jishnub](#):
>
> Perhaps [GitHub - JuliaArrays/EndpointRanges.jl: Julia package for doing arithmetic on endpoints in array indexing](https://github.com/JuliaArrays/EndpointRanges.jl) might help with this?

Yes! Thank you for the information!

With that package, I can fulfill all my needs:

```julia
using EndpointRanges

a1 = 1:11
a3 = reshape(1:(3*2*4), 3, 2, 4)

s1 = (ibegin:3:iend, ) # 1D slice object
s3 = (2, :, ibegin:3:iend) # 3D slice object

b1 = a1[s1...] # get the slice
b3 = a3[s3...] # get the slice

display(collect(b1))
display(collect(b3))

```

With this, one could modify `Base.getindex` and `Base.view` as suggested by @mikmoore .
