-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Revert missing to nothings #245
Conversation
#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.
The test failure seems real. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For interface checks, you want nothing instead of missing because you want to handle the cases.
I'd just like to add that other languages like Rust and C++17 have some form of Optional
s for this reason.
There are Julia packages for this too, but Union{T,Nothing}
does most of the same thing. It's doesn't force you to manually extract the T
, which would make it a little more obvious when you don't do it, but both still throw an error when you try to use it incorrectly (one with an explicit variation of "empty optional" error, the other with a method error).
I think this sort of explicitness makes larger codebases easier to maintain and read.
Maintenance ease is due to error messages closer to the source, as well as clearer error messages.
I also view these known_
methods as more for package development / trying to write optimized library code than I do for their use in throw-away scripts, where being slick and ease of writing lots of functioning code are a priority.
Of course, my actual approval is conditional on tests passing. |
@chriselrod should |
No, it should return an |
but the 1 and the 10 aren't static? |
It's an |
MWE: struct Wrapper{T,N,P<:AbstractArray{T,N}} <: ArrayInterface.AbstractArray2{T,N}
parent::P
end
ArrayInterface.parent_type(::Type{<:Wrapper{T,N,P}}) where {T,N,P} = P
Base.parent(x::Wrapper) = x.parent
ArrayInterface.device(::Type{T}) where {T<:Wrapper} = ArrayInterface.device(parent_type(T))
x = zeros(100);
A = Wrapper(reshape(view(x, 1:60), (3,4,5)));
B = A .== 0; MethodError: no method matching *(::Nothing)
Closest candidates are:
*(::Any, !Matched::Any, !Matched::Any, !Matched::Any...) at C:\Users\accou\AppData\Local\Programs\Julia-1.7.0\share\julia\base\operators.jl:655
*(!Matched::T, !Matched::T) where T<:Union{Int128, UInt128} at C:\Users\accou\AppData\Local\Programs\Julia-1.7.0\share\julia\base\int.jl:967
*(!Matched::T, !Matched::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} at C:\Users\accou\AppData\Local\Programs\Julia-1.7.0\share\julia\base\int.jl:88
...
prod(x::Tuple{Nothing}) at tuple.jl:499
_maybe_known_length(#unused#::Base.HasShape{1}, #unused#::Type{Base.OneTo{Int64}}) at ArrayInterface.jl:96
known_length(#unused#::Type{Base.OneTo{Int64}}) at ArrayInterface.jl:95
known_length(x::Base.OneTo{Int64}) at ArrayInterface.jl:89
maybe_static at int.jl:121 [inlined]
static_length at ArrayInterface.jl:38 [inlined]
map at tuple.jl:223 [inlined]
_maybe_size(#unused#::Base.HasShape{3}, a::Wrapper{Float64, 3, Base.ReshapedArray{Float64, 3, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}, Tuple{}}}) at size.jl:20
size(a::Wrapper{Float64, 3, Base.ReshapedArray{Float64, 3, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}, Tuple{}}}) at size.jl:19
_to_linear at indexing.jl:6 [inlined]
unsafe_getindex(::Wrapper{Float64, 3, Base.ReshapedArray{Float64, 3, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}, Tuple{}}}, ::Int64, ::Int64, ::Vararg{Int64}) at indexing.jl:335
getindex(A::Wrapper{Float64, 3, Base.ReshapedArray{Float64, 3, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}, Tuple{}}}, args::CartesianIndex{3}) at indexing.jl:308
getindex at ArrayInterface.jl:607 [inlined]
_broadcast_getindex at broadcast.jl:636 [inlined]
_getindex at broadcast.jl:666 [inlined]
_broadcast_getindex at broadcast.jl:642 [inlined]
getindex at broadcast.jl:597 [inlined]
macro expansion at broadcast.jl:961 [inlined]
macro expansion at simdloop.jl:77 [inlined]
copyto! at broadcast.jl:960 [inlined]
copyto! at broadcast.jl:971 [inlined]
copyto! at broadcast.jl:913 [inlined]
copy at broadcast.jl:885 [inlined]
materialize(bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{3}, Nothing, typeof(==), Tuple{Wrapper{Float64, 3, Base.ReshapedArray{Float64, 3, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}, Tuple{}}}, Int64}}) at broadcast.jl:860
top-level scope at test.jl:15
eval at boot.jl:373 [inlined] |
It turns out that AbstractArray2 was just pretty broken. size(a::A) where {A} = _maybe_size(Base.IteratorSize(A), a)
_maybe_size(::Base.HasShape{N}, a::A) where {N,A} = map(static_length, axes(a))
known_length(x) = known_length(typeof(x))
known_length(::Type{T}) where {T} = _maybe_known_length(Base.IteratorSize(T), T) which |
@chriselrod what should I do about that? |
Tests pass locally, but it breaks the range code. I'll try and undo that. |
Codecov Report
@@ Coverage Diff @@
## master #245 +/- ##
==========================================
+ Coverage 89.23% 89.31% +0.07%
==========================================
Files 11 11
Lines 1728 1740 +12
==========================================
+ Hits 1542 1554 +12
Misses 186 186
Continue to review full report at Codecov.
|
I made local changes because of type inference failures. Turns out I get those on ArrayInterface 4 (on Julia master) anyway, so I'll revert. |
#232 was found to be a huge mistake. For interface checks, you want
nothing
instead ofmissing
because you want to handle the cases. The issue withmissing
is that it propagates,missing + 1 == missing
. We don't want that here, we want clear and precise error messages at the spot where thenothing
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.