Now that I realize that the concrete-abstract thing doesn’t explain why F1 works, I have a different approach and it’s a little alarming. F2 is actually missing a method.
julia> methods(F1)
# 3 methods for type constructor:
[1] F1() in Main at REPL[2]:1
[2] F1(x::NamedTuple{(:a,), Tuple{A}} where A<:Real) in Main at REPL[1]:2
[3] F1(x) in Main at REPL[2]:1
julia> methods(F2)
# 2 methods for type constructor:
[1] F2() in Main at REPL[3]:3
[2] F2(x) in Main at REPL[3]:3
The documentation claims that the following types have equivalent methods, but it doesn’t pan out in a similar way:
julia> struct T1
x::Int64
end
julia> struct T2
x::Int64
T2(x) = new(x)
end
julia> methods(T1) # both implicit inner, new in @code_warntype
# 2 methods for type constructor:
[1] T1(x::Int64) in Main at REPL[6]:2
[2] T1(x) in Main at REPL[6]:2
julia> methods(T2) # explicit inner
# 1 method for type constructor:
[1] T2(x) in Main at REPL[7]:3
With parameters it’s a bit more complicated so I’ll collapse it:
Example with type parameters
julia> struct Point{T<:Real}
x::T
y::T
end
julia> struct Point2{T<:Real}
x::T
y::T
Point2{T}(x,y) where {T<:Real} = new(x,y)
end
julia> methods(Point) # implicit outer(?) new not in @code_warntype
# 1 method for type constructor:
[1] Point(x::T, y::T) where T<:Real in Main at REPL[10]:2
julia> methods(Point{Real}) # implicit inner
# 1 method for type constructor:
[1] Point{T}(x, y) where T<:Real in Main at REPL[10]:2
julia> methods(Point2)
# 0 methods for type constructor
julia> methods(Point2{Real}) # explicit inner
# 1 method for type constructor:
[1] Point2{T}(x, y) where T<:Real in Main at REPL[11]:4
I can’t tell which of these methods are inner vs outer, but it’s clear the documented methods aren’t actually equivalent to what is implicitly generated, it consistently misses the implicit method with arguments sharing annotations with the fields.
The thing is, I can’t figure out what that implicit method does, it’s not just new(x)
.
struct F22 # based on F2
x::NamedTuple{(:a,), Tuple{A}} where {A<:Real}
F22(x::NamedTuple{(:a,), Tuple{A}} where {A<:Real}) = new(x)
F22(x=(a=NaN,)) = F22(x) # dispatches to first inner method
end
F22() # T not defined
struct F12 # based on F1
x::NamedTuple{(:a,), Tuple{A}} where {A<:Real}
F12(x::NamedTuple{(:a,), Tuple{A}} where {A<:Real}) = new(x)
end
F12(x=(a=NaN,)) = F12(x)
F12() # T not defined