Skip to content

Commit daed820

Browse files
Revert missing to nothings
#232 was found to be a huge mistake. For interface checks, you want `nothing` instead of `missing` because you want to handle the cases. The issue with `missing` is that it propagates, `missing + 1 == missing`. We don't want that here, we want clear and precise error messages at the spot where the `nothing` is found if it's not supposed to be there and it's supposed to be handled. That is antithetical to most of its usage here. So this is a strong revert with a breaking update, which should fix downstream libraries (LoopVectorization, OrdinaryDiffEq, etc.) which were never received the proper downstream PRs from the original change anyways.
1 parent 63617dd commit daed820

File tree

13 files changed

+148
-148
lines changed

13 files changed

+148
-148
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ArrayInterface"
22
uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
3-
version = "4.0.4"
3+
version = "5.0.0"
44

55
[deps]
66
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"

docs/src/index.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ julia> ArrayInterface.size(a)
4444
(static(1), 3)
4545

4646
julia> ArrayInterface.known_size(typeof(a))
47-
(1, missing)
47+
(1, nothing)
4848

4949
```
5050

@@ -62,8 +62,8 @@ Methods should avoid forcing conversion to static sizes when dynamic sizes could
6262
Fore example, `fxn(x) = _fxn(Static.static(ArrayInterface.size(x)), x)` would result in dynamic dispatch if `x` is an instance of `Matrix`.
6363
Additionally, `ArrayInterface.size` should only be used outside of generated functions to avoid possible world age issues.
6464

65-
Generally, `ArrayInterface.size` uses the return of `known_size` to form a static value for those dimensions with known length and only queries dimensions corresponding to `missing`.
66-
For example, the previous example had a known size of `(1, missing)`.
65+
Generally, `ArrayInterface.size` uses the return of `known_size` to form a static value for those dimensions with known length and only queries dimensions corresponding to `nothing`.
66+
For example, the previous example had a known size of `(1, nothing)`.
6767
Therefore, `ArrayInterface.size` would have compile time information about the first dimension returned as `static(1)` and would only look up the size of the second dimension at run time.
6868
This means the above example `ArrayInterface.size(a)` would lower to code similar to this at compile time: `Static.StaticInt(1), Base.arraysize(x, 1)`.
6969
Generic support for `ArrayInterface.known_size` relies on calling `known_length` for each type returned from `axes_types`.
@@ -108,13 +108,13 @@ ArrayInterface.dimnames(::StaticDimnames{dnames}) where {dnames} = static(dnames
108108
struct DynamicDimnames{N}
109109
dimnames::NTuple{N,Symbol}
110110
end
111-
ArrayInterface.known_dimnames(::Type{DynamicDimnames{N}}) where {N} = ntuple(_-> missing, Val(N))
111+
ArrayInterface.known_dimnames(::Type{DynamicDimnames{N}}) where {N} = ntuple(_-> nothing, Val(N))
112112
ArrayInterface.dimnames(x::DynamicDimnames) = getfield(x, :dimnames)
113113

114114
```
115115

116-
Notice that `DynamicDimnames` returns `missing` instead of a symbol for each dimension.
117-
This indicates dimension names are present for `DynamicDimnames` but that information is missing at compile time.
116+
Notice that `DynamicDimnames` returns `nothing` instead of a symbol for each dimension.
117+
This indicates dimension names are present for `DynamicDimnames` but that information is nothing at compile time.
118118

119119
Dimension names should be appropriately propagated between nested arrays using `ArrayInterface.to_parent_dims`.
120120
This allows types such as `SubArray` and `PermutedDimsArray` to work with named dimensions.
@@ -166,7 +166,7 @@ using ArrayInterface: axes_types, parent_type, to_dims
166166
for dim in 1:ndims(A)
167167
# offset relative to parent array
168168
O = relative_known_offsets(A, dim)
169-
if O === missing # offset is not known at compile time and is an `Int`
169+
if O === nothing # offset is not known at compile time and is an `Int`
170170
push!(out.args, :(IdOffsetRange{Int, axes_types($P, $(static(dim)))}))
171171
else # offset is known, therefore it is a `StaticInt`
172172
push!(out.args, :(IdOffsetRange{StaticInt{$O}, axes_types($P, $(static(dim))}))

src/ArrayInterface.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ buffer(x::SparseMatrixCSC) = getfield(x, :nzval)
8181
buffer(x::SparseVector) = getfield(x, :nzval)
8282

8383
"""
84-
known_length(::Type{T}) -> Union{Int,Missing}
84+
known_length(::Type{T}) -> Union{Int,Nothing}
8585
8686
If `length` of an instance of type `T` is known at compile time, return it.
87-
Otherwise, return `missing`.
87+
Otherwise, return `nothing`.
8888
"""
8989
known_length(x) = known_length(typeof(x))
9090
known_length(::Type{<:NamedTuple{L}}) where {L} = length(L)
@@ -94,7 +94,7 @@ known_length(::Type{<:Number}) = 1
9494
known_length(::Type{<:AbstractCartesianIndex{N}}) where {N} = N
9595
known_length(::Type{T}) where {T} = _maybe_known_length(Base.IteratorSize(T), T)
9696
_maybe_known_length(::Base.HasShape, ::Type{T}) where {T} = prod(known_size(T))
97-
_maybe_known_length(::Base.IteratorSize, ::Type) = missing
97+
_maybe_known_length(::Base.IteratorSize, ::Type) = nothing
9898
function known_length(::Type{<:Iterators.Flatten{I}}) where {I}
9999
known_length(I) * known_length(eltype(I))
100100
end
@@ -415,10 +415,10 @@ Indicates the most efficient way to access elements from the collection in low-l
415415
For `GPUArrays`, will return `ArrayInterface.GPU()`.
416416
For `AbstractArray` supporting a `pointer` method, returns `ArrayInterface.CPUPointer()`.
417417
For other `AbstractArray`s and `Tuple`s, returns `ArrayInterface.CPUIndex()`.
418-
Otherwise, returns `missing`.
418+
Otherwise, returns `nothing`.
419419
"""
420420
device(A) = device(typeof(A))
421-
device(::Type) = missing
421+
device(::Type) = nothing
422422
device(::Type{<:Tuple}) = CPUTuple()
423423
device(::Type{T}) where {T<:Array} = CPUPointer()
424424
device(::Type{T}) where {T<:AbstractArray} = _device(has_parent(T), T)
@@ -597,7 +597,7 @@ end
597597

598598
function Base.length(A::AbstractArray2)
599599
len = known_length(A)
600-
if len === missing
600+
if len === nothing
601601
return Int(prod(size(A)))
602602
else
603603
return Int(len)
@@ -1136,7 +1136,7 @@ function __init__()
11361136
Static.eachop_tuple(_offset_axis_type, Static.nstatic(Val(ndims(T))), ArrayInterface.parent_type(T))
11371137
end
11381138
function ArrayInterface.known_offsets(::Type{A}) where {A<:OffsetArrays.OffsetArray}
1139-
ntuple(identity -> missing, Val(ndims(A)))
1139+
ntuple(identity -> nothing, Val(ndims(A)))
11401140
end
11411141
function ArrayInterface.offsets(A::OffsetArrays.OffsetArray)
11421142
map(+, ArrayInterface.offsets(parent(A)), relative_offsets(A))

src/axes.jl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ function axes_types(::Type{T}) where {T<:PermutedDimsArray}
4141
eachop_tuple(field_type, to_parent_dims(T), axes_types(parent_type(T)))
4242
end
4343
function axes_types(::Type{T}) where {T<:AbstractRange}
44-
if known_length(T) === missing
44+
if known_length(T) === nothing
4545
return Tuple{OneTo{Int}}
4646
else
4747
return Tuple{SOneTo{known_length(T)}}
@@ -62,7 +62,7 @@ end
6262
function _non_reshaped_axis_type(::Type{A}, d::StaticInt{D}) where {A,D}
6363
paxis = axes_types(parent_type(A), d)
6464
if D === 1
65-
if known_length(paxis) === missing
65+
if known_length(paxis) === nothing
6666
return paxis
6767
else
6868
return SOneTo{div(known_length(paxis) * sizeof(eltype(parent_type(A))), sizeof(eltype(A)))}
@@ -191,7 +191,7 @@ end
191191
# For now we just make sure the linear elements are accurate.
192192
parent_type(::Type{LazyAxis{:,P}}) where {P<:Array} = OneTo{Int}
193193
@inline function parent_type(::Type{LazyAxis{:,P}}) where {P}
194-
if known_length(P) === missing
194+
if known_length(P) === nothing
195195
return OptionallyStaticUnitRange{StaticInt{1},Int}
196196
else
197197
return SOneTo{known_length(P)}
@@ -208,14 +208,14 @@ known_first(::Type{LazyAxis{N,P}}) where {N,P} = known_offsets(P, static(N))
208208
known_first(::Type{LazyAxis{:,P}}) where {P} = 1
209209
Base.firstindex(x::LazyAxis) = first(x)
210210
@inline function Base.first(x::LazyAxis{N})::Int where {N}
211-
if known_first(x) === missing
211+
if known_first(x) === nothing
212212
return Int(offsets(parent(x), static(N)))
213213
else
214214
return Int(known_first(x))
215215
end
216216
end
217217
@inline function Base.first(x::LazyAxis{:})::Int
218-
if known_first(x) === missing
218+
if known_first(x) === nothing
219219
return first(parent(x))
220220
else
221221
return known_first(x)
@@ -225,20 +225,20 @@ known_last(::Type{LazyAxis{N,P}}) where {N,P} = known_last(axes_types(P, static(
225225
known_last(::Type{LazyAxis{:,P}}) where {P} = known_length(P)
226226
Base.lastindex(x::LazyAxis) = last(x)
227227
Base.last(x::LazyAxis) = _last(known_last(x), x)
228-
_last(::Missing, x) = last(parent(x))
228+
_last(::Nothing, x) = last(parent(x))
229229
_last(N::Int, x) = N
230230

231231
known_length(::Type{LazyAxis{N,P}}) where {N,P} = known_size(P, static(N))
232232
known_length(::Type{LazyAxis{:,P}}) where {P} = known_length(P)
233233
@inline function Base.length(x::LazyAxis{N})::Int where {N}
234-
if known_length(x) === missing
234+
if known_length(x) === nothing
235235
return size(getfield(x, :parent), static(N))
236236
else
237237
return known_length(x)
238238
end
239239
end
240240
@inline function Base.length(x::LazyAxis{:})::Int
241-
if known_length(x) === missing
241+
if known_length(x) === nothing
242242
return length(parent(x))
243243
else
244244
return known_length(x)
@@ -254,7 +254,7 @@ Base.axes1(x::Slice{<:LazyAxis}) = indices(parent(x.indices))
254254
Base.to_shape(x::LazyAxis) = length(x)
255255

256256
@inline function Base.checkindex(::Type{Bool}, x::LazyAxis, i::Integer)
257-
if known_first(x) === missing || known_last(x) === missing
257+
if known_first(x) === nothing || known_last(x) === nothing
258258
return checkindex(Bool, parent(x), i)
259259
else # everything is static so we don't have to retrieve the axis
260260
return (!(known_first(x) > i) || !(known_last(x) < i))

src/dimensions.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ _is_named(x::NTuple{N,Symbol}) where {N} = x !== _nunderscore(Val(N))
160160
_is_named(::Any) = true
161161

162162
"""
163-
known_dimnames(::Type{T}) -> Tuple{Vararg{Union{Symbol,Missing}}}
164-
known_dimnames(::Type{T}, dim::Union{Int,StaticInt}) -> Union{Symbol,Missing}
163+
known_dimnames(::Type{T}) -> Tuple{Vararg{Union{Symbol,Nothing}}}
164+
known_dimnames(::Type{T}, dim::Union{Int,StaticInt}) -> Union{Symbol,Nothing}
165165
166166
Return the names of the dimensions for `x`. `:_` is used to indicate a dimension does not
167167
have a name.
@@ -229,7 +229,7 @@ An error is thrown if any keywords are used which do not occur in `nda`'s names.
229229
230230
1. parse into static dimnension names and key words.
231231
2. find each dimnames in key words
232-
3. if missing is found use Colon()
232+
3. if nothing is found use Colon()
233233
4. if (ndims - ncolon) === nkwargs then all were found, else error
234234
=#
235235
@generated function find_all_dimnames(x::Tuple{Vararg{Any,ND}}, nd::Tuple{Vararg{Any,NI}}, inds::Tuple, default) where {ND,NI}

src/indexing.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ previously executed `to_index(old_axis, arg) -> index`. `to_axis` assumes that
277277
"""
278278
@inline function to_axis(axis, inds)
279279
if !can_change_size(axis) &&
280-
(known_length(inds) !== missing && known_length(axis) === known_length(inds))
280+
(known_length(inds) !== nothing && known_length(axis) === known_length(inds))
281281
return axis
282282
else
283283
return to_axis(IndexStyle(axis), axis, inds)

src/ranges.jl

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11

22
_cartesian_index(i::Tuple{Vararg{Int}}) = CartesianIndex(i)
3-
_cartesian_index(::Any) = missing
3+
_cartesian_index(::Any) = nothing
44

55
"""
6-
known_first(::Type{T}) -> Union{Int,Missing}
6+
known_first(::Type{T}) -> Union{Int,Nothing}
77
88
If `first` of an instance of type `T` is known at compile time, return it.
9-
Otherwise, return `missing`.
9+
Otherwise, return `nothing`.
1010
1111
```julia
1212
julia> ArrayInterface.known_first(typeof(1:4))
13-
missing
13+
nothing
1414
1515
julia> ArrayInterface.known_first(typeof(Base.OneTo(4)))
1616
1
@@ -19,7 +19,7 @@ julia> ArrayInterface.known_first(typeof(Base.OneTo(4)))
1919
known_first(x) = known_first(typeof(x))
2020
function known_first(::Type{T}) where {T}
2121
if parent_type(T) <: T
22-
return missing
22+
return nothing
2323
else
2424
return known_first(parent_type(T))
2525
end
@@ -30,14 +30,14 @@ function known_first(::Type{T}) where {N,R,T<:CartesianIndices{N,R}}
3030
end
3131

3232
"""
33-
known_last(::Type{T}) -> Union{Int,Missing}
33+
known_last(::Type{T}) -> Union{Int,Nothing}
3434
3535
If `last` of an instance of type `T` is known at compile time, return it.
36-
Otherwise, return `missing`.
36+
Otherwise, return `nothing`.
3737
3838
```julia
3939
julia> ArrayInterface.known_last(typeof(1:4))
40-
missing
40+
nothing
4141
4242
julia> ArrayInterface.known_first(typeof(static(1):static(4)))
4343
4
@@ -47,7 +47,7 @@ julia> ArrayInterface.known_first(typeof(static(1):static(4)))
4747
known_last(x) = known_last(typeof(x))
4848
function known_last(::Type{T}) where {T}
4949
if parent_type(T) <: T
50-
return missing
50+
return nothing
5151
else
5252
return known_last(parent_type(T))
5353
end
@@ -57,14 +57,14 @@ function known_last(::Type{T}) where {N,R,T<:CartesianIndices{N,R}}
5757
end
5858

5959
"""
60-
known_step(::Type{T}) -> Union{Int,Missing}
60+
known_step(::Type{T}) -> Union{Int,Nothing}
6161
6262
If `step` of an instance of type `T` is known at compile time, return it.
63-
Otherwise, return `missing`.
63+
Otherwise, return `nothing`.
6464
6565
```julia
6666
julia> ArrayInterface.known_step(typeof(1:2:8))
67-
missing
67+
nothing
6868
6969
julia> ArrayInterface.known_step(typeof(1:4))
7070
1
@@ -74,7 +74,7 @@ julia> ArrayInterface.known_step(typeof(1:4))
7474
known_step(x) = known_step(typeof(x))
7575
function known_step(::Type{T}) where {T}
7676
if parent_type(T) <: T
77-
return missing
77+
return nothing
7878
else
7979
return known_step(parent_type(T))
8080
end
@@ -215,21 +215,21 @@ known_last(::Type{<:OptionallyStaticUnitRange{<:Any,StaticInt{L}}}) where {L} =
215215
known_last(::Type{<:OptionallyStaticStepRange{<:Any,<:Any,StaticInt{L}}}) where {L} = L::Int
216216

217217
@inline function Base.first(r::OptionallyStaticRange)::Int
218-
if known_first(r) === missing
218+
if known_first(r) === nothing
219219
return getfield(r, :start)
220220
else
221221
return known_first(r)
222222
end
223223
end
224224
function Base.step(r::OptionallyStaticStepRange)::Int
225-
if known_step(r) === missing
225+
if known_step(r) === nothing
226226
return getfield(r, :step)
227227
else
228228
return known_step(r)
229229
end
230230
end
231231
@inline function Base.last(r::OptionallyStaticRange)::Int
232-
if known_last(r) === missing
232+
if known_last(r) === nothing
233233
return getfield(r, :stop)
234234
else
235235
return known_last(r)
@@ -306,9 +306,9 @@ end
306306

307307
@noinline unequal_error(x,y) = @assert false "Unequal Indices: x == $x != $y == y"
308308
@inline check_equal(x, y) = x == y || unequal_error(x,y)
309-
_try_static(::Missing, ::Missing) = missing
310-
_try_static(x::Int, ::Missing) = x
311-
_try_static(::Missing, y::Int) = y
309+
_try_static(::Nothing, ::Nothing) = nothing
310+
_try_static(x::Int, ::Nothing) = x
311+
_try_static(::Nothing, y::Int) = y
312312
@inline _try_static(::StaticInt{N}, ::StaticInt{N}) where {N} = StaticInt{N}()
313313
@inline function _try_static(::StaticInt{M}, ::StaticInt{N}) where {M,N}
314314
@assert false "Unequal Indices: StaticInt{$M}() != StaticInt{$N}()"
@@ -330,7 +330,7 @@ Base.lastindex(x::OptionallyStaticRange) = length(x)
330330
end
331331
end
332332
Base.length(r::OptionallyStaticStepRange) = _range_length(first(r), step(r), last(r))
333-
_range_length(start, s, stop) = missing
333+
_range_length(start, s, stop) = nothing
334334
@inline function _range_length(start::Int, s::Int, stop::Int)
335335
if s > 0
336336
if stop < start # isempty

src/size.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ size(a::Array, dim::Integer) = Base.arraysize(a, convert(Int, dim))
5656
function size(a::A, dim::Integer) where {A}
5757
if parent_type(A) <: A
5858
len = known_size(A, dim)
59-
if len === missing
59+
if len === nothing
6060
return Int(length(axes(a, dim)))
6161
else
6262
return StaticInt(len)
@@ -77,10 +77,10 @@ size(x::Iterators.Zip) = Static.reduce_tup(promote_shape, map(size, getfield(x,
7777

7878
"""
7979
known_size(::Type{T}) -> Tuple
80-
known_size(::Type{T}, dim) -> Union{Int,Missing}
80+
known_size(::Type{T}, dim) -> Union{Int,Nothing}
8181
8282
Returns the size of each dimension of `A` or along dimension `dim` of `A` that is known at
83-
compile time. If a dimension does not have a known size along a dimension then `missing` is
83+
compile time. If a dimension does not have a known size along a dimension then `nothing` is
8484
returned in its position.
8585
"""
8686
known_size(x) = known_size(typeof(x))
@@ -98,10 +98,10 @@ end
9898

9999
# 1. `Zip` doesn't check that its collections are compatible (same size) at construction,
100100
# but we assume as much b/c otherwise it will error while iterating. So we promote to the
101-
# known size if matching a `Missing` and `Int` size.
101+
# known size if matching a `Nothing` and `Int` size.
102102
# 2. `promote_shape(::Tuple{Vararg{CanonicalInt}}, ::Tuple{Vararg{CanonicalInt}})` promotes
103103
# trailing dimensions (which must be of size 1), to `static(1)`. We want to stick to
104-
# `Missing` and `Int` types, so we do one last pass to ensure everything is dynamic
104+
# `Nothing` and `Int` types, so we do one last pass to ensure everything is dynamic
105105
@inline function known_size(::Type{<:Iterators.Zip{T}}) where {T}
106106
dynamic(reduce_tup(_promote_shape, eachop(_unzip_size, nstatic(Val(known_length(T))), T)))
107107
end

0 commit comments

Comments
 (0)