# Package for arbitrary \`getindex\` function?

**URL:** <https://discourse.julialang.org/t/package-for-arbitrary-getindex-function/69034>\
**Category:** General Usage\
**Tags:** arrays\
**Created:** [October 1, 2021, 9:33am UTC](https://discourse.julialang.org/t/package-for-arbitrary-getindex-function/69034 "2021-10-01T09:33:19Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [October 1, 2021, 9:33am UTC](https://discourse.julialang.org/t/package-for-arbitrary-getindex-function/69034/1 "2021-10-01T09:33:19Z")

</div>

Does anyone know if we have an array package that lets you specify an arbitrary `getindex` function? Implementing it is pretty trivial; aside from tests, this is a complete package:

```julia
module ClosureArrays

export ClosureArray

struct ClosureArray{T,N,F,P,Axs} <: AbstractArray{T,N}
    getindex::F
    parent::P
    axes::Axs
end
ClosureArray{T}(getindex::F, parent, axes) where {T,F} =
    ClosureArray{T, length(axes), F, typeof(parent), typeof(axes)}(getindex, parent, axes)
ClosureArray(getindex::F, parent, axes) where F =
    ClosureArray{Base._return_type(getindex, Tuple{typeof(parent), Vararg{Int, length(axes)}})}(getindex, parent, axes)

Base.@propagate_inbounds Base.getindex(A::ClosureArray{T,N}, i::Vararg{Int,N}) where {T,N} =
    convert(T, A.getindex(A.parent, i...))::T
Base.size(A::ClosureArray) = map(length, A.axes)
Base.axes(A::ClosureArray) = A.axes

end

```

and here would be a demo of an array that reverses the dimensions (mimicking `PermutedDimsArray`):

```julia
julia> P = rand(3,5,4);

julia> A = ClosureArray(P, reverse(axes(P))) do AA, i...
           AA[reverse(i)...]
       end;

julia> A[3,2,1] == P[1,2,3]
true

```

and another that lazily sums along dimension 2:

```julia
julia> A = ClosureArray(P, (axes(P, 1), axes(P, 3))) do AA, i1, i2
           sum(view(AA, i1, :, i2))
       end;

julia> size(A)
(3, 4)

julia> A[1, 3] == sum(P[1, :, 3])
true

```

If we don’t have this already, I can add ClosureArrays to JuliaArrays. (Or should it be called GetindexArrays?)

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [October 1, 2021, 9:57am UTC](https://discourse.julialang.org/t/package-for-arbitrary-getindex-function/69034/2 "2021-10-01T09:57:14Z")

</div>

I don’t know a package that implements this. I am curious, why do you explicitly store `parent`? What I expected was:

```julia
struct GetindexArray{...} <: ...
    f::F
    axes::Axes
end
Base.getindex(A::GetindexArray, I...) = A.f(I...)

A = GetindexArray((axes(P, 1), axes(P, 3))) do i1, i2
           sum(view(P, i1, :, i2))
       end;

```

I think I also have seen that variant in a package, but I don’t remember where.

---

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [October 1, 2021, 9:58am UTC](https://discourse.julialang.org/t/package-for-arbitrary-getindex-function/69034/3 "2021-10-01T09:58:18Z")

</div>

What does `P` reference inside the `do` block?

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [October 1, 2021, 9:58am UTC](https://discourse.julialang.org/t/package-for-arbitrary-getindex-function/69034/4 "2021-10-01T09:58:46Z")

</div>

It is a capture `P = rand(3,5,4)`.

---

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [October 1, 2021, 10:00am UTC](https://discourse.julialang.org/t/package-for-arbitrary-getindex-function/69034/5 "2021-10-01T10:00:26Z")

</div>

If you do that at the command line, it’s a non-const global variable capture. I thought it would be nice to support efficient processing no matter where the parent comes from.

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [October 1, 2021, 10:08am UTC](https://discourse.julialang.org/t/package-for-arbitrary-getindex-function/69034/6 "2021-10-01T10:08:46Z")

</div>

> [@tim.holy](#):
>
> I thought it would be nice to support efficient processing no matter where the parent comes from.

Efficiency is indeed nice and that’s a pragmatic solution. Thanks!
