The second one performs a conversion before assigning to
xand is equivalent > tox = convert(T, foo())::T
Perhaps you meant this?
x::T = convert(T, foo())
Afaik, the return value of convert is already of type T and it does not need to be asserted. The difference is important for the discussion as x::T guarantees that x will not change type until it goes end of scope.
Indeed, convert may be called. It is only called though when there is something to convert. A function annotated with ::S returning a local variable of type S will not induce a call to convert. So the performance hit is absent in this case. We expect that developers will not introduce a lot of convert methods for other cases.
julia> import Base.convert
julia> struct S
mem::Int64
end
julia> function convert(::Type{S}, x::Any)::S
println("convert(...): Started.")
return S(x)
end
convert (generic function with 196 methods)
julia> function return_right_type(s::S)::S
return S(s.mem * s.mem)
end
return_right_type (generic function with 1 method)
julia> u::S = return_right_type(S(42))
S(1764)
julia> v::S = 5
convert(...): Started.
5
julia>