Using views to mutate parts of arrays

I’m playing around with Julia 1.0.3 and getting confused. I have written a function that mutates an array. I want to use this function to mutate a part of a larger array. I can’t wrap my head around why some things work and some don’t. Here are examples:

function f!(x)
    for i in eachindex(x)
        x[i] = i
    end
end

x = randn(2, 3)
f!(view(x, :, :))
x

These work:

f!(view(x, :, :))
f!(view(x, 1, :))
f!(view(x, :, axes(x, 2)))
f!(view(x, 1, 1:2))

But these does not work:

f!(view(x, 1:2, 1:2))
f!(view(x, 1, 1))
f!(view(x, 1:2, 1:3))
f!(view(x, axes(x, 1), axes(x, 2)))
f!(view(x, axes(x, 1), :))

I don’t spot the pattern. Please help me understand.

The problem is that eachindex may return a CartesianIndex that can’t be stored back into an array of floats

> x = randn(2, 3)
> eachindex(view(x,1:2,1:2))
2×2 CartesianIndices{2,Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}}:
 CartesianIndex(1, 1)  CartesianIndex(1, 2)
 CartesianIndex(2, 1)  CartesianIndex(2, 2)

If x is an array of Any, your mutating function works as is

> x = Array{Any}(undef,2,3)
> f!(view(x,1:2,1:2))
> x
2×3 Array{Any,2}:
 CartesianIndex(1, 1)  CartesianIndex(1, 2)  #undef
 CartesianIndex(2, 1)  CartesianIndex(2, 2)  #undef

You can explicitly ask for linear (integer) indexes using eachindex(IndexLinear(),x) (these would probably be a bit less efficient for arbitrary views, since the iteration logic is more complicated).

1 Like

Of course, how silly of me.
Thank you!