# Indexing with \`CartesianIndex\`

**URL:** <https://discourse.julialang.org/t/indexing-with-cartesianindex/26615>\
**Category:** Internals & Design\
**Tags:** question\
**Created:** [July 22, 2019, 12:07am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615 "2019-07-22T00:07:04Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [July 22, 2019, 12:07am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/1 "2019-07-22T00:07:04Z")

</div>

Consider this code:

```julia
julia> 1[]
1

julia> 1[CartesianIndex()]
1

julia> Ref(1)[]
1

julia> Ref(1)[CartesianIndex()]
ERROR: MethodError: no method matching getindex(::Base.RefValue{Int64}, ::CartesianIndex{0})

```

Is there a reason why sometimes `CartesianIndex()` indexing for `0`-dimensional containers is sometimes allowed and sometimes it is not allowed?

PS. As usual this is DataFrames.jl related (see [https://github.com/JuliaData/DataFrames.jl/pull/1890/files#diff-57cbbe702db7443003fc8c590f239d70R173](https://github.com/JuliaData/DataFrames.jl/pull/1890/files#diff-57cbbe702db7443003fc8c590f239d70R173) where I initially wanted to use `CartesianIndex()` but it failed in some cases).

---

<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 22, 2019, 12:46am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/2 "2019-07-22T00:46:51Z")

</div>

CartesianIndex indexing only works by default for arrays. We’ve explicitly enabled it for some other array-like objects, like `Number`s and `getindex(t::Tuple, i::CartesianIndex{1})`. Ref is probably another good candidate.

The reason it’s sometimes allowed and sometimes not is simply that not all indexable collections are multidimensional or array-like at all, so we can’t do it by default for everyone. For example, it doesn’t make sense to do anything special with CartesianIndex for dictionaries. Thus we need to decide on a case-by-case basis if the non-array thing should act array-like… and how much so.

Tuples are a good example. They support some array-like things — including one-dimensional cartesian indices and non-scalar slicing — but they don’t support `t[]` or `t[CartesianIndex()]` or `t[:,:]`. All of those things would work with `t = [1]` but don’t with `t = (1,)`. Deciding exactly where that line should land can be a tough call.

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [July 22, 2019, 1:38am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/3 "2019-07-22T01:38:02Z")

</div>

> [@mbauman](#):
>
> The reason it’s sometimes allowed and sometimes not is simply that not all indexable collections are multidimensional or array-like at all, so we can’t do it by default for everyone

I was just chatting to @andyferris about this very thing yesterday. He mentioned in passing that he wanted multidimensional dictionary like objects to work. He had some interesting motivation related to tensor networks but I admit to not following it as well as I should 🙂

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [July 22, 2019, 9:18am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/4 "2019-07-22T09:18:29Z")

</div>

I get your point. My idea was rather of a contract like:

If something has `axes` then it should be indexable using `CartesianIndex`. And `Ref` is an example of such case, when this contract currently breaks.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 22, 2019, 9:34am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/5 "2019-07-22T09:34:57Z")

</div>

I don’t think having a method (`axes(::X)`) imply that some other method exists or is applicable (`getindex(::X, ::CartesianIndex)`) is a usual convention in Julia.

[Interfaces](https://docs.julialang.org/en/v1/manual/interfaces/) are usually defined with _abstract types_ or _traits_.

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [July 22, 2019, 10:06am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/6 "2019-07-22T10:06:35Z")

</div>

My point is exactly that `axes` is a part of `AbstractArray` interface. If you define `axes` but do not define `CartesianIndex` indexing then you are not fully implementing the contract of the interface.

The contract for `axes` in Base is:

> Return the tuple of valid indices for array A.

so it should not be defined for an object that is not an array (or pretends to be an array by fulfilling the contract).

Of course you are allowed to do this in Julia, but I would think that in Base we should be consistent.

Now why it is important - broadcasting by default uses `CartesianIndex` then some object is allowed to be broadcasted over (as it supports `axes`), but later fails if it does not support `CartesianIndex` indexing. This is exactly the case for `Ref` currently.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 22, 2019, 10:36am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/7 "2019-07-22T10:36:47Z")

</div>

> [@bkamins](#):
>
> If you define `axes` but do not define `CartesianIndex` indexing then you are not fully implementing the contract of the interface.

My point was that _defining a method associated with an interface does not imply that a particular interface applies_ — it has to be made explicit by either traits or abstract types.

Eg think about `size` — having it defined does not mean that the abstract array interface applies (`Base` has examples of this for types which implement iteration, but not the array interface).

However, I think that in the specific case `Ref` could implement the method you suggested.

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [July 22, 2019, 10:41am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/8 "2019-07-22T10:41:11Z")

</div>

I agree with you, it is just a matter of consistency in Base.

Just for a reference from my code n DataFrames.jl and the issue it raises. `bcf` in it is a `Broadcasted{AbstractArrayStyle{0}}` object:

```julia
v = bcf.f(getindex.(bcf.args)...)

```

works but

```julia
v = bcf.f(getindex.(bcf.args, Ref(CartesianIndex()))...)

```

does not work.

And you assume that if something is in the `bcf.args` collection (and passed earlier tests) it should be array-like and these two codes should be equivalent.

---

<div class="post-metadata">

**Author:** ![andyferris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyferris/32/235_2.png) [@andyferris](https://discourse.julialang.org/u/andyferris)\
**Post date:** [July 23, 2019, 1:34am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/9 "2019-07-23T01:34:05Z")

</div>

Yes I think the question is of consistency - why define `axes` if you never support multidimensional indexing? What is the semantics of the result? What can I _do_ with `x` where `x = axes(y)`? Is this meant to be a `broadcast` thing?

I think its disingenious to say that `axes` itself is not an interface. Sure, it’s a small part of the larger `AbstractArray` interface but it should provide guarantees of its own (it returns a `Tuple`, for example, the length of the tuple determines the dimensionality of the container which probably shouldn’t disagree with `ndims`, etc, etc). @Tamas_Papp in a duck-typed world we don’t always want to rely on abstract types and we haven’t yet fleshed out a set of traits to define _most_ the interfaces in `Base` (AFAICT we can’t even describe the majority of variances of behavior of the `AbstractArray`s provided by `Base` and the standard libs).

Anyway, as @c42f alluded to, yes I think there might be value to gain by thinking about how multidimensional indexing fits into containers beyond `AbstractArray`, what traits we use to describe the capabilities of containers in general, etc.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 23, 2019, 5:52am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/10 "2019-07-23T05:52:57Z")

</div>

Just to clarify: I think that _in this particular case_, `Ref` should support the whole `AbstractArray` interface, even if technically it is not a subtype.

_In general_, however, I don’t think that relying on the presence of various methods is a good strategy to determine if something follows an interface, because the set of methods for interfaces can overlap (eg `size`).

And yes, this implies that we need to be more careful about defining and documenting interfaces (eg allowing queries with traits). The last big change in this direction was [#11794](https://github.com/JuliaLang/julia/pull/11794), which was a great improvement, but it does not have to be the last one. A lot of implicit interfaces in Julia are underdocumented, which makes it difficult to rely on and extend them.

---

<div class="post-metadata">

**Author:** ![andyferris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyferris/32/235_2.png) [@andyferris](https://discourse.julialang.org/u/andyferris)\
**Post date:** [July 23, 2019, 6:10am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/11 "2019-07-23T06:10:38Z")

</div>

> `Ref` should support the whole `AbstractArray` interface

This seems somewhat reasonable (but I note we are reluctant with other fundamental types like `Tuple`).

Going from the opposite direction… I’ve been curious about the question of if we can make the binary representation of `Array{0,T}` to be the same as `Ref{T}`? (Since `Array{0,T}` already seems like a good place to store and manipulate a single value, but the flexible higher-dimensional array representation in C is a little “heavier” than seems strictly necessary in zero-D).

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 23, 2019, 6:17am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/12 "2019-07-23T06:17:38Z")

</div>

I would prefer a separate wrapper type, eg `Scalar{T}`. IMO reusing `Ref` for this purpose is just confusing.

---

<div class="post-metadata">

**Author:** ![andyferris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyferris/32/235_2.png) [@andyferris](https://discourse.julialang.org/u/andyferris)\
**Post date:** [July 23, 2019, 6:38am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/13 "2019-07-23T06:38:36Z")

</div>

Sorry, I didn’t understand. Can you expand?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 23, 2019, 6:50am UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/14 "2019-07-23T06:50:11Z")

</div>

I think that `Ref` was designed for a [purpose that is unrelated to broadcasting](https://docs.julialang.org/en/v1/base/c/), and its use for broadcasting is not ideal (basically, a pun).

I would prefer the introduction of a wrapper type, eg

```julia
struct Scalar{T}
    value::T
end

```

that would take its place. Whether to introduce surface syntax for it (eg `&value`, as proposed in [#27608](https://github.com/JuliaLang/julia/pull/27608), is an orthogonal issue). Ideally, users who don’t use it for its original purpose would never ever encounter `Ref`.

As for 0-dimensional arrays, I think it is a cute corner case and we should support them for consistency, but would prefer to have a wrapper type that signals intent instead of using them for wrapping “scalars”.

---

<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 23, 2019, 5:52pm UTC](https://discourse.julialang.org/t/indexing-with-cartesianindex/26615/15 "2019-07-23T17:52:05Z")

</div>

> [@Tamas\_Papp](#):
>
> Whether to introduce surface syntax for it (eg `&value` , as proposed in [#27608](https://github.com/JuliaLang/julia/pull/27608), is an orthogonal issue)

It wasn’t orthogonal at all in terms of the design decision. It was a proposed horse trade that never happened — we wanted the `&x` syntax to work equally well for both ccall and broadcast, and the best way to make sure both of those things could use that syntax was to use `Ref` for both.
