It appears that julia master has changed a behavior from previous versions, and now size
for an AbstractRange
is defined as (length(r),)
instead of the previous behavior where length
was defined as prod(size(r))
. This makes length
a more fundamental function than size
, which, fair enough, seems to be the right thing for 1D arrays. However this puts AbstractRange
s at odds with AbstractVector
s, since AbstractVector
s rely on the previous behavior. As an exampe:
julia> struct CustomArray{T,N,A<:AbstractArray{T,N}} <: AbstractArray{T,N}
parent :: A
end
julia> Base.size(a::CustomArray) = size(a.parent)
julia> Base.axes(a::CustomArray) = axes(a.parent)
julia> Base.getindex(a::CustomArray{<:Any,N}, i::Vararg{Int,N}) where {N} = getindex(a.parent, i...)
julia> CustomArray(3:4)
2-element CustomArray{Int64, 1, UnitRange{Int64}}:
3
4
julia> CustomArray(3:4) |> length
2
julia> CustomArray(3:4) isa AbstractVector
true
this works correctly on nightly. Now
julia> struct CustomRange{T,A<:AbstractRange{T}} <: AbstractRange{T}
parent :: A
end
julia> Base.size(a::CustomRange) = size(a.parent)
julia> Base.axes(a::CustomRange) = axes(a.parent)
julia> Base.getindex(a::CustomRange, i::Int) where {N} = getindex(a.parent, i)
julia> Base.step(a::CustomRange) = step(a.parent)
julia> CustomRange(3:4)
3:1:4
julia> CustomRange(3:4) |> length
ERROR: length implementation missing
[...]
julia> CustomRange(3:4) isa AbstractVector
true
It’s a bit nonintuitive that for AbstractRange
s one needs to define length
whereas for AbstractVector
s one needs to define size
. Although breakages caused by this change may be explained as “missing methods”, perhaps this behavior should be documented better if this is the intent? Should one always define both methods anyway, even though this might be redundant?