Tuples of CartesianIndex and broadcasting

While I can broadcast scalars, like

``````julia> 1 .+ (2, 3)
(3, 4)
``````

I can’t do the same with `CartesianIndex`s:

``````julia> CartesianIndex(1,1) .+ (CartesianIndex(2,2), CartesianIndex(3,3))
ERROR: iteration is deliberately unsupported for CartesianIndex. Use `I` rather than `I...`, or use `Tuple(I)...`
Stacktrace:
[1] error(::String) at ./error.jl:33
[2] iterate(::CartesianIndex{2}) at ./multidimensional.jl:166
[3] copyto!(::Array{Int64,1}, ::CartesianIndex{2}) at ./abstractarray.jl:733
[4] _collect(::UnitRange{Int64}, ::CartesianIndex{2}, ::Base.HasEltype, ::Base.HasLength) at ./array.jl:630
[5] collect(::CartesianIndex{2}) at ./array.jl:624
[8] top-level scope at REPL[15]:1
``````

I understand that `1 .+ CartesianIndex(1,1)` fails, but since `CartesianIndex(1,1) + CartesianIndex(1,1)` is fine, I would expect the above example to work. Is the behavior intended, or a bug?

(I can of course write

``````julia> (CartesianIndex(1,1),) .+ (CartesianIndex(2,2), CartesianIndex(3,3))
(CartesianIndex(3, 3), CartesianIndex(4, 4))
``````

instead. But that’s less elegant… and beside the point.)

1 Like

I think the problem there is that there is a possible ambiguity on whether the broadcast is over the indexes of the tuple or the indexes of the CartesianIndex.

1 Like

Hmm… But since broadcasting over the indexes of the `CartesianIndex` is not allowed (`1 .+ CartesianIndex(1,1)` errors), I would assume that we are left with only one possibility, no?

1 Like

You can write `Ref(CartesianIndex(1,1)) .+ stuff` to protect it from the broadcast. (Similar to `(... ,)`, as I see now you said.) I think the way to specify that a type is always scalar with respect to broadcasting is

``````Broadcast.broadcastable(I::CartesianIndex) = Ref(I)
``````

I wonder if it would break anything to define this?

1 Like

We’ve been hesitant to make CartesianIndexes collection-like (that is, iterable and broadcastable) because their reason for being is the they represent a single location. Generally I’ll just convert them to Tuples when I want to treat them as a list of indices.

Maybe I’m misunderstanding, but I’m arguing for the opposite, namely to treat CartesianIndexes as “single locations”/scalars “all the way” (i.e. not collection-like). If that were the case, my example above would not fail…

Oh, you’re absolutely right! 90% of the requests we get for this are the other way, and I simply didn’t read closely enough.

Yes, I think making it broadcast like a scalar would be reasonable — and nonbreaking since it errors now.

5 Likes

Well, I’m a 100% with the 10% then

Should I file an issue?