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 AbstractRanges at odds with AbstractVectors, since AbstractVectors 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 AbstractRanges one needs to define length whereas for AbstractVectors 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?