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