I have a (mutable, edit) struct with a field that has type Union{T, Nothing}
, and I've been trying to implement Base.isless
for this struct, but I cannot figure out how to make JET.jl happy...
A simple function works fine,
julia> function foo(a::Union{Int, Nothing}, b::Union{Int, Nothing})
if a isa Nothing
if b isa Nothing
return false
else
return true
end
else
if b isa Nothing
return false
else
return a < b
end
end
end
foo (generic function with 1 method)
julia> JET.@report_opt foo(1, 2)
No errors detected
julia> JET.@report_call foo(1,2)
No errors detected
But once the a
and b
are encapsulated in a struct, JET complains:
julia> mutable struct Bar
x::Union{Int, Nothing}
end
julia> function Base.isless(a::Bar, b::Bar)
if a.x isa Nothing
if b.x isa Nothing
return false
else
return true
end
else
if b.x isa Nothing
return false
else
return a.x < b.x
end
end
end
julia> JET.@report_opt Base.isless(Bar(1), Bar(2))
═════ 2 possible errors found ═════
┌ isless(a::Bar, b::Bar) @ Main ./REPL[16]:12
│┌ <(x::Int64, y::Nothing) @ Base ./operators.jl:343
││ runtime dispatch detected: isless(x::Int64, y::Nothing)
│└────────────────────
│┌ <(x::Nothing, y::Int64) @ Base ./operators.jl:343
││ runtime dispatch detected: isless(x::Nothing, y::Int64)
│└────────────────────
julia> JET.@report_call Base.isless(Bar(1), Bar(2))
═════ 3 possible errors found ═════
┌ isless(a::Bar, b::Bar) @ Main ./REPL[16]:12
│┌ <(x::Nothing, y::Nothing) @ Base ./operators.jl:343
││ no matching method found `isless(::Nothing, ::Nothing)`: isless(x::Nothing, y::Nothing)
│└────────────────────
│┌ <(x::Int64, y::Nothing) @ Base ./operators.jl:343
││ no matching method found `isless(::Int64, ::Nothing)`: isless(x::Int64, y::Nothing)
│└────────────────────
│┌ <(x::Nothing, y::Int64) @ Base ./operators.jl:343
││ no matching method found `isless(::Nothing, ::Int64)`: isless(x::Nothing, y::Int64)
│└────────────────────
Using JET v0.8.9 on Julia v1.9.2.
Any ideas?
... I guess JET.@report_opt
is already telling me, quite clearly, that it ends up in dynamic dispatch..., so of course making the Bar field type a type parameter <: Union{Int, Nothing}
works...
julia> mutable struct Bar{T<:Union{Int, Nothing}}
x::T
end
julia> function Base.isless(a::Bar, b::Bar)
if a.x isa Nothing
if b.x isa Nothing
return false
else
return true
end
else
if b.x isa Nothing
return false
else
return a.x < b.x
end
end
end
julia> using JET
julia> JET.@report_opt Base.isless(Bar(1), Bar(2))
No errors detected
julia> JET.@report_call Base.isless(Bar(1), Bar(2))
No errors detected
... but that's not what I was looking for - I would like to be able to modify the field - make it a Nothing and vice versa...
Last updated: Oct 02 2023 at 04:34 UTC