Consider the issue of annotating types of objects taken from unknown sources. The following are two solutions to this problem:
function test1(a::Vector{Any})
x = a[1]::Int
2*x
end
and
function test2(a::Vector{Any})
x = convert(Int, a[1])
2*x
end
The manual recommends the first solution in the Performance-Tips section. It seems to me that the second solution might be preferable in many instances because the resulting code has greater genericity. But @code_warntype on test2 gave me many more warnings than on test1– it reported that x and 2*x in test2 were both of type Any. (Julia 0.5.2).
Why does the compiler not know the types in test2?
convert is just a normal function — it doesn’t have any special sauce besides a very strong convention that convert(T, x) returns something of type T. Just like calling all other functions with an unknown argument, Julia doesn’t know exactly which method of convert will be called, and so it can’t make any assumptions about the return type.
The type assertion a[1]::T, on the other hand, will error if a[1] is anything but T, meaning that Julia can conclusively determine that every time control flow successfully passes the assertion a[1] is a T.
Thanks for the explanation. In retrospect, this makes perfect sense.
As a general matter, I worry that Julia’s great flexibility (such as the flexibility to define a convert(T,x::X) that returns a non-T) opens up many pitfalls for the user. But this particular piece of flexibility seems potentially useful. So I have just submitted a PR for the manual to explain the point.
I proposed a solution (untested!) to the original poster’s problem. The solution involved a constructor for a type S that returned a non-S. I believe that this is permitted by the language. Meanwhile, there is a close relationship between constructors and convert. So I can imagine that there are situations for constructing complex types in which defining convert(T,x) to return a non-T might be useful.