Open sethaxen opened 1 year ago
As this functionality was seemingly designed mostly for OffsetArrays.jl: https://github.com/JuliaLang/julia/blob/ce292c1ba4f5ec771479228169383f6378d35d45/base/abstractarray.jl#L839-L844
it should be noted that this does not produce an error when OffsetArrays.jl is loaded and it's type pirated methods are available.
julia> using OffsetArrays
julia> stack(A2)
4×3×2 OffsetArray(::Array{Float64, 3}, 1:4, 1:3, 1:2) with eltype Float64 with indices 1:4×1:3×1:2:
[:, :, 1] =
0.488586 -1.93562 -0.225797
-0.307972 -1.7415 0.316024
0.0702133 1.00626 1.00785
-0.72046 -0.679983 0.00612942
[:, :, 2] =
-1.59223 0.291592 1.48481
-1.87154 -0.727295 0.378543
-1.08153 1.35971 1.63377
0.819348 -0.132509 -1.36885
julia> stack(A3)
4×3×2 OffsetArray(::Array{Float64, 3}, 1:4, 1:3, 1:2) with eltype Float64 with indices 1:4×1:3×1:2:
[:, :, 1] =
-1.13547 0.695512 -0.0426222
0.296079 1.85618 -0.247409
-0.879178 -0.417559 -0.447225
-0.791633 0.283552 -0.221949
[:, :, 2] =
-0.76631 0.116022 1.31183
-1.00218 2.7132 0.148179
0.0976066 0.551973 -1.16329
-0.966548 0.382295 0.341279
Meaning e.g. DimensionalData.jl tests on stack
will pass because it tests against OffsetArrays.jl. But stack
will not work in a fresh session without OffsetArrays.jl loaded.
stack
seems like a distraction here.
With the above MyArray type, similar
with a mix of its special axes and ordinary Base.OneTo
fails:
julia> let x = MyArrayType.MyArray([1,2,3])
similar(x, Int, axes(x)..., axes([4,5])...) # dispatches to Base's mix-of-ranges-and-Int method
end
ERROR: MethodError: no method matching similar(::Main.MyArrayType.MyArray{Int64, 1}, ::Type{Int64}, ::Tuple{Base.Slice{Main.MyArrayType.URange{Int64}}, Int64})
Stacktrace:
[1] similar(::Main.MyArrayType.MyArray{Int64, 1}, ::Type{Int64}, ::Base.Slice{Main.MyArrayType.URange{Int64}}, ::Base.OneTo{Int64})
@ Base ./abstractarray.jl:838
[2] top-level scope
@ REPL[4]:2
julia> using OffsetArrays # this supplies the missing method, so exactly the same code now runs:
julia> let x = MyArrayType.MyArray([1,2,3])
similar(x, Int, axes(x)..., axes([4,5])...)
end
3×2 OffsetArray(::Matrix{Int64}, 1:3, 1:2) with eltype Int64 with indices 1:3×1:2:
5648757792 0
0 5648757760
4780822496 0
If you want similar
to notice your special axis type, I would have thought you ought to define methods accepting at least one of this special type, mixed with Base types. Rather the only covering the case when all axes are your special type. (Not sure why it's Slice{URange}
here but that doesn't matter.) I see now that the docs recommend only the same-type similar
.
Adding ever more methods to similar
isn't a very extensible mechanism. It can't work if two packages both try it. Perhaps it could be replaced by something more like to_indices
which peels them off one by one. Or perhaps it could use promotion, with a method to catch all mixed cases which calls similar(x,T,promote(axes...)...)
.
When arrays that use custom index types as suggested in the docs are passed to
stack
, everything works if the wrapped array uses the same custom index type. However, if the inner and outer arrays have different index types, an error is raised on this line:https://github.com/JuliaLang/julia/blob/ce292c1ba4f5ec771479228169383f6378d35d45/base/abstractarray.jl#L2792
This calls the following
similar
fallback, which replacesBase.OneTo
axes withInt
s, creating a mixture ofInt
s and custom indices for which nosimilar
method is defined:https://github.com/JuliaLang/julia/blob/ce292c1ba4f5ec771479228169383f6378d35d45/base/abstractarray.jl#L839-L844
(it seems that following the instructions in the comment would both be type-piracy and create ambiguities)
Here's an minimal example where we define a custom array type that uses custom indices as defined in CustomUnitRanges.jl and then call
stack
on these arrays: