# Ordinal Indexing as a Language Feature

**URL:** <https://discourse.julialang.org/t/ordinal-indexing-as-a-language-feature/91970>\
**Category:** Internals & Design\
**Created:** [December 21, 2022, 5:07pm UTC](https://discourse.julialang.org/t/ordinal-indexing-as-a-language-feature/91970 "2022-12-21T17:07:56Z")\
**Posts on this page:** 7\
**Page:** 2

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [December 27, 2022, 5:53am UTC](https://discourse.julialang.org/t/ordinal-indexing-as-a-language-feature/91970/22 "2022-12-27T05:53:49Z")

</div>

Hah, good to know 😅

Even if claiming `ordinal` might be okayish, I’m still finding it difficult to imagine how the interface of literally every ordered collection could be respecified in a satisfactory way that wouldn’t also be considered hugely breaking, by any agreeable notion of what “breaking” means. Maybe I’m just unimaginative, but I’m having trouble here.

Part of me is also beginning to suspect that the notion of ordinal indices for ordered collections is somehow related to the notion of tokens for unordered collections.

---

<div class="post-metadata">

**Author:** ![ParadaCarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paradacarleton/32/20005_2.png) [@ParadaCarleton](https://discourse.julialang.org/u/ParadaCarleton)\
**Post date:** [December 27, 2022, 8:22pm UTC](https://discourse.julialang.org/t/ordinal-indexing-as-a-language-feature/91970/23 "2022-12-27T20:22:09Z")

</div>

> [@uniment](#):
>
> In order for a change to be non-breaking, it would mean that no code breaks.

The definition of a breaking change in software is a bit weird–it means something that breaks a _promise_ you made in an earlier version of software, not something that could conceivably break a piece of code. As far as I’m aware, the Julia devs haven’t promised never to add new identifiers to the language.

Namespacing should also keep this from breaking anything. If you define `th = 1` in a function, the local variable `th` refers to something different from the `th` object.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [December 27, 2022, 9:14pm UTC](https://discourse.julialang.org/t/ordinal-indexing-as-a-language-feature/91970/24 "2022-12-27T21:14:47Z")

</div>

I should’ve re-read the [PSA](https://discourse.julialang.org/t/psa-julia-is-not-at-that-stage-of-development-anymore/44872) 😅 This opens things up quite a bit.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [December 28, 2022, 10:33am UTC](https://discourse.julialang.org/t/ordinal-indexing-as-a-language-feature/91970/25 "2022-12-28T10:33:09Z")

</div>

> [@uniment](#):
>
> I’m still finding it difficult to imagine how the interface of literally every ordered collection could be respecified in a satisfactory way that wouldn’t also be considered hugely breaking

Per usual, this was an ignorant comment. A brief look into how it’s currently done (since I hadn’t looked into it until now):

Base has the function `Base.to_indices` for arrays, which OrdinalIndexing.jl overloads to convert ordinal indices into cardinal indices. Example with the simpler `Base.to_index`:

```julia
julia> struct Foo end

julia> Base.to_index(x::AbstractArray, ::Foo) = firstindex(x) + 1

julia> [1,2,3][Foo()]
2

```

This is what enables it to work without having to overload all the `Base.getindex` methods for `AbstractArray` types (and deal with all the dispatch ambiguities that would pose).

For the `AbstractRange` type, OrdinalIndexing.jl overloads the `Base.getindex` and `Base.view` methods as necessary.

So if we want ordinal indices to work with other ordered collections, this demonstrates two paths:

1. specify that `Base.to_indices` should become part of their interface, or
2. specify appropriate `Base.getindex` and `Base.view` methods for ordinal indices

Neither of these seems _that_ breaking, although it seems like #1 is better to avoid dispatch ambiguities…

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 8, 2023, 8:40am UTC](https://discourse.julialang.org/t/ordinal-indexing-as-a-language-feature/91970/26 "2023-01-08T08:40:53Z")

</div>

## _Another idea_

What if `ordinal` wasn’t a helper to construct indices, but to construct an _ordinally-indexed view_?

```julia
g(a, b) = let (a, b)=ordinal.((a, b)), (il, jl)=size(a)
    sum(a[i,j]+b[i,j] for i=2:il-1, j=2:jl-1)
end

```

Then undecorated 1-based indexing could have a roaring comeback; just set up views at the entrance and index how you wish.

Basically, an undo button for `OffsetArray`s 😁.

---

<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:** [January 8, 2023, 11:07am UTC](https://discourse.julialang.org/t/ordinal-indexing-as-a-language-feature/91970/27 "2023-01-08T11:07:59Z")

</div>

`reshape` does this already:

```julia
julia> A = OffsetArray(reshape(1:4, 2, 2), 3:4, 5:6)
2×2 OffsetArray(reshape(::UnitRange{Int64}, 2, 2), 3:4, 5:6) with eltype Int64 with indices 3:4×5:6:
 1 3
 2 4

julia> reshape(A, size(A)) # same array, but with 1-based indices
2×2 reshape(::UnitRange{Int64}, 2, 2) with eltype Int64:
 1 3
 2 4

```

This doesn’t always work, though, and `OffsetArrays.no_offset_view` is guaranteed to produce 1-based views.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 9, 2023, 7:45pm UTC](https://discourse.julialang.org/t/ordinal-indexing-as-a-language-feature/91970/28 "2023-01-09T19:45:15Z")

</div>

Indeed `OffsetArrays.no_offset_view` produces exactly this idea, but that doesn’t solve the issue that gets some people to ponder [whether OffsetArrays.jl is a poison pill](https://discourse.julialang.org/t/is-offsetarrays-jl-a-poison-pill/85188/). Namely, we would ideally have _something in_ `Base` _which offers assurance that 1-based indices will work on an arbitrary_ `AbstractArray`.

This is exactly what OrdinalIndices.jl provides by offering an _ordinal index type_. I’m toying with the alternative approach of using an _ordinally indexed view_, that `ordinal(A)` will be a 1-based-indexed view of `A`.

Apparently this idea was already [pondered here](https://discourse.julialang.org/t/is-offsetarrays-jl-a-poison-pill/85188/21) but deserves more exploration imo. It would be really easy to add it to the `AbstractArray` specification, and the fallback method is the easiest thing in the world.

```julia
ordinal(A::AbstractArray) = A

```

this would place the burden on `OffsetArrays` to add the method:

```julia
ordinal(A::OffsetArray) = ordinal(OffsetArrays.no_offset_view(A))

```

[Previous page](https://discourse.julialang.org/t/ordinal-indexing-as-a-language-feature/91970.md?page=1)
