# AbstractVector vs AbstractRange: length vs size -- which is fundamental?

**URL:** <https://discourse.julialang.org/t/abstractvector-vs-abstractrange-length-vs-size-which-is-fundamental/64689>\
**Category:** Internals & Design\
**Tags:** question, array, interface, range\
**Created:** [July 15, 2021, 12:45pm UTC](https://discourse.julialang.org/t/abstractvector-vs-abstractrange-length-vs-size-which-is-fundamental/64689 "2021-07-15T12:45:22Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [July 15, 2021, 12:45pm UTC](https://discourse.julialang.org/t/abstractvector-vs-abstractrange-length-vs-size-which-is-fundamental/64689/1 "2021-07-15T12:45:22Z")

</div>

It appears that julia master has [changed a behavior](https://github.com/JuliaLang/julia/pull/41479) 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
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
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?

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [July 18, 2022, 6:04pm UTC](https://discourse.julialang.org/t/abstractvector-vs-abstractrange-length-vs-size-which-is-fundamental/64689/2 "2022-07-18T18:04:27Z")

</div>

This came up for a suggested topic and went unanswered.

According to the Base interfaces documentation, for iterators `length` is more fundamental for general iterators since your options are:

1. Do not implement either `length` or `size` if `Base.IteratorSize(IterType) in (Base.IsInfinite(), Base.SizeUnknown()) `.
2. Implement just `length` if `Base.IteratorSize(IterType) == Base.HasLength()`
3. Implement `length` and `size` if `Base.IteratorSize(IterType) isa Base.HasShape`

[https://docs.julialang.org/en/v1/manual/interfaces/](https://docs.julialang.org/en/v1/manual/interfaces/)

---

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [July 18, 2022, 6:44pm UTC](https://discourse.julialang.org/t/abstractvector-vs-abstractrange-length-vs-size-which-is-fundamental/64689/3 "2022-07-18T18:44:45Z")

</div>

`AbstractArray`s such as ranges definitely fall in type-3, for which presumably we need to define both `length` and `size`. The only issue that remains is that the docstring for `length(A::AbstractArray)` states that it defaults to `prod(size(A))`, which seems to indicate that `length` comes for free with `size`. Maybe the docstring doesn’t need to specify this, especially if the expectation is that `length` needs to be implemented by the developer.

---

<div class="post-metadata">

**Author:** ![nalimilan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nalimilan/32/147_2.png) [@nalimilan](https://discourse.julialang.org/u/nalimilan)\
**Post date:** [July 28, 2022, 9:01pm UTC](https://discourse.julialang.org/t/abstractvector-vs-abstractrange-length-vs-size-which-is-fundamental/64689/4 "2022-07-28T21:01:17Z")

</div>

The fallback for `length(::AbstractArray)` is useful. What’s problematic here is that there’s a specific method for `AbstractRange`s which throws an error, which is inconsistent with other `AbstractArray`s.

Maybe this should be discussed on the PR which introduced this:  
[https://github.com/JuliaLang/julia/pull/40382](https://github.com/JuliaLang/julia/pull/40382)  
CC: @jameson
