# copy(::CartesianIndices)

`copy(x::CartesianIndices)` and `copy(x::LinearIndices)` do not return the same type as the input argument.

I guess you could argue that it doesn’t make sense to copy an immutable. But perhaps you could also argue that trying to copy an immutable should either return the correct type or result in a “no matching method” error.

There is a precedent for defining `copy` for immutables. Here’s a definition for copying ranges from Base:

``````# Ranges are immutable
copy(r::AbstractRange) = r
``````

So let’s try copying `CartesianIndices` and `LinearIndices`

``````dims = ntuple(d -> -1:1, 2)
CIs = CartesianIndices(dims)
LIs = LinearIndices(CIs)
``````
``````julia> copy(CIs)
3×3 Array{CartesianIndex{2},2}:
CartesianIndex(-1, -1)  CartesianIndex(-1, 0)  CartesianIndex(-1, 1)
CartesianIndex(0, -1)   CartesianIndex(0, 0)   CartesianIndex(0, 1)
CartesianIndex(1, -1)   CartesianIndex(1, 0)   CartesianIndex(1, 1)

julia> copy(LIs)
3×3 Array{Int64,2}:
1  4  7
2  5  8
3  6  9
``````

The fallback for `copy` seems to go through `similar` which returns an `Array` for these types.

For non-standard indexing, an `OffsetArray` is returned (if `OffsetArrays` are in scope, otherwise there’s a no method matching error).

Summary
``````dims = ntuple(d -> -1:1, 2)
CIs = CartesianIndices(Base.IdentityUnitRange.(dims))
LIs = LinearIndices(CIs)
``````
``````julia> copy(CIs)
ERROR: MethodError: no method matching similar(::CartesianIndices{2,Tuple{Base.IdentityUnitRange{UnitRange{Int64}},Base.IdentityUnitRange{UnitRange{Int64}}}}, ::Type{CartesianIndex{2}}, ::Tuple{Base.IdentityUnitRange{UnitRange{Int64}},Base.IdentityUnitRange{UnitRange{Int64}}})
Closest candidates are:
similar(::AbstractArray, ::Type{T}) where T at abstractarray.jl:629
similar(::AbstractArray, ::Type{T}, ::Union{Integer, AbstractUnitRange}...) where T at abstractarray.jl:632
similar(::AbstractArray, ::Type{T}, ::Tuple{Vararg{Int64,N}}) where {T, N} at abstractarray.jl:640
...
Stacktrace:
[1] similar(::CartesianIndices{2,Tuple{Base.IdentityUnitRange{UnitRange{Int64}},Base.IdentityUnitRange{UnitRange{Int64}}}}, ::Type{CartesianIndex{2}}) at .\abstractarray.jl:629
[2] similar(::CartesianIndices{2,Tuple{Base.IdentityUnitRange{UnitRange{Int64}},Base.IdentityUnitRange{UnitRange{Int64}}}}) at .\abstractarray.jl:628
[3] copymutable at .\abstractarray.jl:971 [inlined]
[4] copy(::CartesianIndices{2,Tuple{Base.IdentityUnitRange{UnitRange{Int64}},Base.IdentityUnitRange{UnitRange{Int64}}}}) at .\abstractarray.jl:915
[5] top-level scope at REPL[4]:1

julia> copy(LIs)
ERROR: MethodError: no method matching similar(::LinearIndices{2,Tuple{Base.IdentityUnitRange{UnitRange{Int64}},Base.IdentityUnitRange{UnitRange{Int64}}}}, ::Type{Int64}, ::Tuple{Base.IdentityUnitRange{UnitRange{Int64}},Base.IdentityUnitRange{UnitRange{Int64}}})
Closest candidates are:
similar(::AbstractArray, ::Type{T}) where T at abstractarray.jl:629
similar(::AbstractArray, ::Type{T}, ::Union{Integer, AbstractUnitRange}...) where T at abstractarray.jl:632
similar(::AbstractArray, ::Type{T}, ::Tuple{Vararg{Int64,N}}) where {T, N} at abstractarray.jl:640
...
Stacktrace:
[1] similar(::LinearIndices{2,Tuple{Base.IdentityUnitRange{UnitRange{Int64}},Base.IdentityUnitRange{UnitRange{Int64}}}}, ::Type{Int64}) at .\abstractarray.jl:629
[2] similar(::LinearIndices{2,Tuple{Base.IdentityUnitRange{UnitRange{Int64}},Base.IdentityUnitRange{UnitRange{Int64}}}}) at .\abstractarray.jl:628
[3] copymutable at .\abstractarray.jl:971 [inlined]
[4] copy(::LinearIndices{2,Tuple{Base.IdentityUnitRange{UnitRange{Int64}},Base.IdentityUnitRange{UnitRange{Int64}}}}) at .\abstractarray.jl:915
[5] top-level scope at REPL[5]:1
``````

Would it make sense to define the following `copy` methods?

``````Base.copy(x::CartesianIndices) = x
Base.copy(x::LinearIndices) = x
``````

My opinion is that `copy(x) = x` is the right thing for immutables. While it is a useless operation if you know that `x` is immutable, it can be useful in generic code. I think it would be nice to just open a PR to julialang/julia with the proposed change.

Why is it useful for generic code? The reason you `copy` is so that you will mutate it later, which will fail for immutables anyway?

`````` Why is it useful for generic code? The reason you copy is so that you will mutate it later, which will fail for immutables anyway?
``````

Or that you want a snapshot of the current version that does not change if the original is mutated.

Almost feels like `deepcopy` is better then.

1 Like

I tend to agree. However I still think relying on copy to return something mutable is a bad idea. E.g. it fails for ranges right now. Also `typeof(copy(x)) != typeof(x)` is a surprise. I think if you want a mutable copy, then you should be explicit about it. Anyway if people are using copy like this, then it is not worth breaking their code. But maybe `copy` docs could be clarified about semantics, e.g. `typeof(copy(x)) != typeof(x)` and mutability.

Yes, this is incorrect. The function that `Base` uses when it needs a mutable copy is `Base.copymutable` (added here: https://github.com/JuliaLang/julia/pull/16620). Maybe it’s time to finally export that function?

Alternatively, `similar` is guaranteed to return a mutable type, so you could use `copy!(similar(a),a)` (at least for arrays — this doesn’t work for generic iterables)… encapsulating that common pattern was precisely why `copymutable` was added.

No:

``````julia> copy(1:10)
1:10
``````

I agree with @greg_plowman that copying `CartesianIndices` or `LinearIndices` should act like copying ranges.

3 Likes

I think you need to elaborate a bit. That looked pointless to me.

Pointless or not, it’s behaved that way for years and it probably can’t be changed before Julia 2.0. `copy` does not guarantee a mutable result, so assuming that property is wrong.

I know it doesn’t guarantee that and I never said that it did. I said that the reason why you want to copy something is because you want to mutate it later. The fact that there are some pointless `copy` methods defined for various types doesn’t change that.

Are you referring to `copy` and `deepcopy` or just `copy`? Because some generic code may need to keep an user-provided object in a way that it is sure it will not be changed externally. In this case, the code does not change the object, nor assume it is mutable, but keeps a `deepcopy` of it because it may be mutable.