# Writing my own custom-indexing array: type piracy from OffsetArrays methods

**URL:** <https://discourse.julialang.org/t/writing-my-own-custom-indexing-array-type-piracy-from-offsetarrays-methods/19939>\
**Category:** General Usage\
**Tags:** array, type-piracy\
**Created:** [January 22, 2019, 4:48pm UTC](https://discourse.julialang.org/t/writing-my-own-custom-indexing-array-type-piracy-from-offsetarrays-methods/19939 "2019-01-22T16:48:28Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![sairus7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sairus7/32/10816_2.png) [@sairus7](https://discourse.julialang.org/u/sairus7)\
**Post date:** [January 22, 2019, 4:48pm UTC](https://discourse.julialang.org/t/writing-my-own-custom-indexing-array-type-piracy-from-offsetarrays-methods/19939/1 "2019-01-22T16:48:28Z")

</div>

I have implemented a simple circular buffer type similar to [this](https://github.com/JuliaCollections/DataStructures.jl/blob/master/src/circular_buffer.jl), but with cumulative indexing, so that it has `offset` field that grows each time an element is pushed back to the full buffer. (That’s why I did not used immutable `OffsetArray` with its `offsets` tuple).

```julia
mutable struct SlidingBuffer{T} <: AbstractVector{T}
    buffer::Vector{T}
    len::Int
    contentLen::Int
    first::Int
    last::Int
    offset::Int
    function SlidingBuffer{T}(len::Int) where T
        new{T}(Vector{T}(undef, len), len, 0, 0, 1, 0, 0)
    end
end

# custom indexing
@inline Base.axes(A::SlidingBuffer) =
    (UnitRange{Int}(A.offset + 1, A.offset + A.contentLen),)

# and other methods from AbstractArray interface ...

```

It behaves in the following way:

```julia
b = SlidingBuffer{Int}(10)
> SlidingBuffer{Int64} with indices 1:0

[push!(b, 123) for _=1:15]
b
> SlidingBuffer{Int64} with indices 6:15:
 123
 123
 123
 123
   ⋮
 123
 123
 123
 123

```

Then, I figured that I miss some `similar` methods from [Interfaces · The Julia Language](https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-array-1)  
and maybe used `UnitRange` instead of `AbstractUnitRange`.

And on some operations, like `b = b*3` these methods are taken from [OffsetArray.jl](https://github.com/JuliaArrays/OffsetArrays.jl/blob/master/src/OffsetArrays.jl) package, automatically converting my buffer to `OffsetArray`, due to this method:

```julia
Base.similar(::Type{T}, shape::Tuple{OffsetAxis,Vararg{OffsetAxis}}) where {T<:AbstractArray} =
    OffsetArray(T(undef, map(indexlength, shape)), map(indexoffset, shape))

```

with `OffsetAxis` broadly defined as:

```julia
const OffsetAxis = Union{Integer, UnitRange, Base.OneTo, IdentityUnitRange}

```

All these function recalls with different types are somewhat confusing. How should I write those `similar` and `axes` methods for my simple buffer type to not have any type inference between packages?

---

<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:** [January 22, 2019, 5:14pm UTC](https://discourse.julialang.org/t/writing-my-own-custom-indexing-array-type-piracy-from-offsetarrays-methods/19939/2 "2019-01-22T17:14:22Z")

</div>

Just a note on terminology: this is an ambiguity as a result of type-piracy. Inference/inferring is what Julia does to figure out types as it’s compiling and is wholly unrelated.

So, yes, OffsetArrays is doing a bit of type-piracy here — it’s defining a method assuming that it’ll be the only offset array package loaded at any given time. It’s generally a “bad thing” to define methods in a package where all the arguments come from other packages — or base itself! It leads to these sorts of situations, where two packages want the same signature. In general we try to design our interfaces such that this isn’t a problem, but this is a case where we’ve not found a great solution. And thus `Base` is coded with the expectation that there is exactly one OffsetArrays package loaded at any given time. You can still work with this, though, if your package depends on OffsetArrays and you define:

```julia
Base.similar(::Type{T}, shape::Tuple{OffsetAxis,Vararg{OffsetAxis}}) where {T<:SlidingBuffer} = ...

```

There are probably other definitions you’ll need here, too. Defining a custom _offset_ array isn’t something that we’ve worked on making simple or easy (yet).

Note that as of Julia 1.1, we’re using `Base.IdentityUnitRange` as the type of offset axes.

---

<div class="post-metadata">

**Author:** ![sairus7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sairus7/32/10816_2.png) [@sairus7](https://discourse.julialang.org/u/sairus7)\
**Post date:** [January 22, 2019, 5:21pm UTC](https://discourse.julialang.org/t/writing-my-own-custom-indexing-array-type-piracy-from-offsetarrays-methods/19939/3 "2019-01-22T17:21:39Z")

</div>

Thank you for explanation!  
Yes, I noted that there is `IdentityUnitRange`, but what’s the point behind it? Also, [tutorial](https://docs.julialang.org/en/v1/devdocs/offset-arrays/) says about using [CustomUnitRanges.jl](https://github.com/JuliaArrays/CustomUnitRanges.jl). So, should I use `IdentityUnitRange` or `URange`, or just stay with `UnitRange`?

---

<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:** [January 22, 2019, 5:39pm UTC](https://discourse.julialang.org/t/writing-my-own-custom-indexing-array-type-piracy-from-offsetarrays-methods/19939/4 "2019-01-22T17:39:27Z")

</div>

Ah, shoot! I missed that documentation when I changed this — that’s now out of date.

We’ve slowly been discovering that if the axes of an offset array are _themselves_ also offset, then it makes a number of one-based algorithms magically work again. In short: it seems that the identity `ax[i] == i` is an important features of 1-based `ax`es. In 1.0 we had used the special `Base.Slice` to provide this property, but it had first been used by SubArray for a slightly different purpose, leading to some strange bugs when we tried to shoehorn both uses together.

Lots more details here:

[https://github.com/JuliaLang/julia/pull/27038](https://github.com/JuliaLang/julia/pull/27038)  
[https://github.com/JuliaLang/julia/pull/28941](https://github.com/JuliaLang/julia/pull/28941)

---

<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:** [January 22, 2019, 7:11pm UTC](https://discourse.julialang.org/t/writing-my-own-custom-indexing-array-type-piracy-from-offsetarrays-methods/19939/5 "2019-01-22T19:11:02Z")

</div>

> [@mbauman](#):
>
> it’s defining a method assuming that it’ll be the only offset array package loaded at any given time

More precisely, it’s doing a bit of piracy and “arrogantly” assuming the mantle of the _default_ offset array package. (It’s probably good to have one of those.) It’s entirely possible to have more than one loaded at once; indeed, because one offset array package is sometimes just not enough 😄, [ImageFiltering.jl](https://github.com/JuliaImages/ImageFiltering.jl) loads OffsetArrays, [CatIndices.jl](https://github.com/JuliaArrays/CatIndices.jl) and [FFTViews.jl](https://github.com/JuliaArrays/FFTViews.jl) at the same time. Because CatIndices and FFTViews define their own AbstractUnitRange types, there is no confusion.
