# Offset array package with offsets in the type?

**URL:** <https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772>\
**Category:** General Usage\
**Created:** [May 27, 2022, 9:41am UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772 "2022-05-27T09:41:18Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [May 27, 2022, 9:41am UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772/1 "2022-05-27T09:41:18Z")

</div>

I’m a bit disappointed to realize that in OffsetArrays the offsets are a struct field instead of a type parameter. Do any alternative packages exist?

---

<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:** [May 27, 2022, 11:36am UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772/2 "2022-05-27T11:36:14Z")

</div>

The offsets are a field instead of in the type to reduce the number of methods that need to be compiled. While I’m not aware of other offset array packages, is there anything specific that you’re trying to achieve by having the offsets in the type? In that case, it might not be too difficult to define a wrapper, and forward certain methods to the parent `OffsetArray`.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [May 27, 2022, 2:27pm UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772/3 "2022-05-27T14:27:37Z")

</div>

I just think it would be nice to be able to offset arrays without worrying about the array member access run time cost. But I’m aware that there’s a tradeoff between compilation time and run time.

In my program, there would be just a single offset array type, so I don’t have to worry about method explosion.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [May 27, 2022, 2:30pm UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772/4 "2022-05-27T14:30:39Z")

</div>

> [@nsajko](#):
>
> In my program, there would be just a single offset array type, so I don’t have to worry about method explosion.

just define your own array with a constant offset then…

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [May 27, 2022, 2:33pm UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772/5 "2022-05-27T14:33:12Z")

</div>

Maybe I’ll do that, but it doesn’t seem straightforward, I’ll have to think about various interfaces that have to be respected.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [May 27, 2022, 2:33pm UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772/6 "2022-05-27T14:33:25Z")

</div>

> [@nsajko](#):
>
> array member access run time cost

array is not tuple, the offset calculation time is really minimal, do you have benchmark showing it being a significant overhead compared to if you encode the offset in types?

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [May 27, 2022, 2:36pm UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772/7 "2022-05-27T14:36:19Z")

</div>

I don’t have benchmarks (I don’t exactly have anything to compare with yet), but it seems like reading the offset values for each access would cause extra data cache misses, while encoding the offsets as part of the type seems like it could enable nice optimizations. I’m just speculating, of course.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [May 27, 2022, 2:41pm UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772/8 "2022-05-27T14:41:13Z")

</div>

> [@nsajko](#):
>
> as part of the type seems like it could enable nice optimizations

I don’t think so, whatever you do, in the end you will call

```julia-auto
getindex(XX, M) -> getindex(OO, N)

```

`XX` is your wrapper type and user did `XX[M]`, and `OO` is the final inner Julia built-in array.

The only question is how to get `N`. Regardless of where the offset is stored, you still need to calculate `N = M + offset`, I really don’t think it will be significant

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [May 27, 2022, 2:43pm UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772/9 "2022-05-27T14:43:25Z")

</div>

The offset addition operation could be encoded in the executable code (not data) or even optimized away, if the offset is a compile time known constant.  
I think the main improvement is eliminating the extra memory access.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [May 27, 2022, 2:48pm UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772/10 "2022-05-27T14:48:25Z")

</div>

> [@nsajko](#):
>
> if the offset is a compile time known constant.

constant folding happens even when it’s not encoded as type:

```julia-auto
julia> struct A
           a::Int
       end

julia> function f(x)
           A1 = A(1)
           return A1.a + x
       end
f (generic function with 1 method)

julia> @code_llvm f(3)
; @ REPL[2]:1 within `f`
define i64 @julia_f_808(i64 signext %0) #0 {
top:
; @ REPL[2]:3 within `f`
; ┌ @ int.jl:87 within `+`
   %1 = add i64 %0, 1
; └
  ret i64 %1
}

```

---

<div class="post-metadata">

**Author:** ![N5N3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/n5n3/32/17663_2.png) [@N5N3](https://discourse.julialang.org/u/N5N3)\
**Post date:** [May 27, 2022, 3:39pm UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772/11 "2022-05-27T15:39:02Z")

</div>

> [@nsajko](#):
>
> I think the main improvement is eliminating the extra memory access.

For a single `getindex`/`setindex!` const offset might help.  
But for most cases, we access the elements many times within a function.  
LLVM might not know the offset value, but it knows it won’t change.  
So the overhead could be ignored for most usecase.

---

<div class="post-metadata">

**Author:** ![JohnnyChen94](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johnnychen94/32/29979_2.png) [@JohnnyChen94](https://discourse.julialang.org/u/JohnnyChen94)\
**Post date:** [May 27, 2022, 6:32pm UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772/12 "2022-05-27T18:32:01Z")

</div>

A fun fact that I don’t know why: OffsetArray of `Array` is sometimes faster than normal `Array` 🤷‍♂️

The issue below checks a simple sum loop over the array

```julia
function arr_sum(X)
    val = zero(eltype(X))
    R = CartesianIndices(X)
    for i in R
        @inbounds val += X[i]
    end
    val
end

```

and you can observe that OffsetArray is basically as fast as Array.

[https://github.com/JuliaLang/julia/issues/38073](https://github.com/JuliaLang/julia/issues/38073)

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [May 27, 2022, 6:43pm UTC](https://discourse.julialang.org/t/offset-array-package-with-offsets-in-the-type/81772/13 "2022-05-27T18:43:45Z")

</div>

Perhaps this has something to do with various alignments within the compiled code? Some of that would vary between Julia restarts, so it might make sense to repeat benchmarks like these, restarting Julia in between.  
There are many other possible benchmarking noise sources, of course, and trying to account for as many as possible can be fun.
