Julia’s documentation recommends to wrap types into Type{...}
for performance considerations
The concrete example in the documentation is
julia> struct WrapType{T}
value::T
end
julia> WrapType(Float64) # default constructor, note DataType
WrapType{DataType}(Float64)
julia> WrapType(::Type{T}) where T = WrapType{Type{T}}(T)
WrapType
julia> WrapType(Float64) # sharpened constructor, note more precise Type{Float64}
WrapType{Type{Float64}}(Float64)
However, trying everything with a plain Wrapper which does not do this Type{...}
support, inference seems to work fully.
julia> struct Wrapper{T}
value::T
end
julia> function f()
a = Wrapper(Int)
a.value
end
f (generic function with 1 method)
julia> Wrapper(Int)
Wrapper{DataType}(Int64)
julia> Base.promote_op(f)
Type{Int64}
Is the example in the documentation outdated? Do all Types have by now extra support for type-inference such that they do not need to be marked with Type{...}
any longer?
That’s likely just constant folding in the specific case. If you add a Wrapper
argument to f
, the inference fails as expected:
julia> function f(b::Wrapper)
a = Wrapper(Int)
promote_type(a.value, b.value)
end
f (generic function with 2 methods)
julia> Base.promote_op(f, typeof(Wrapper(Float64)))
Type{S} where S
5 Likes
Thank you very much for the concise failing example.
Can you even construct an example where it does not depend on passing in typeof(Wrapper(Float64))
to promote_op?
I mean when does Julia’s constant-folding mechanism stop working and falls back to type-level inference only?
Somewhat contrived
function foo()
if rand(Bool)
a = Wrapper(Int)
else
a = Wrapper(Vector{Int})
end
a.value
end
Now Base.promote_op(foo)
returns DataType
and not Union{Type{Int}, Type{Vector{Int}}}
. If a
does not have multiple bind sites, I’m unsure how complex the remaining function must be for constant folding not working. However, constant folding and type inference in general is a compiler optimization not affecting the semantics, so it may change from version to version.
2 Likes
A much more concise (and deterministic!) example:
function foo()
a = Ref(Wrapper(Int))
a[].value
end
julia> Base.promote_op(foo)
DataType
1 Like
thank you both very much for these additional examples.
It helps a lot to see the inference failing in real simple examples