Does return type declaration make function type stable?

Docs read:

Return type declarations are rarely used in Julia: in general, you should instead write “type-stable” functions in which Julia’s compiler can automatically infer the return type. For more information, see the Performance Tips chapter.

Does return type declaration make a function type stable? Or is it just type casting after the function is evaluated?

2 Likes

If the return type can be inferred without declaring it, the declaration wouldn’t do anything. If the return type is different or not inferrable, the declaration adds a convert step before returning, which would fail if not implemented. It does nothing about type instability in the function before the return statement.

4 Likes

How do you mean, "the declaration wouldn’t do anything. "?

Wouldn’t the type annotation overwrite the inferred type?
Has a type declaration not always priority over the inferred type?

Well, if the type is inferred to be the same as the declared one, the declaration has no effect. In all other cases, it takes priority in that the final result will be converted to the declared type, no matter if the function was type stable or not. Thus, it documents the return type, but cannot improve performance or make a function type stable.
Again, it shows that the semantics of Julia are that of a dynamic language with type stability and static dispatch being a performance optimization (that should not change the semantics). In contrast to statically typed languages (which refuse to run ill-typed programs), it’s on the programmer to help that a function is type stable, otherwise it still runs but potentially slower.

6 Likes

As I understand, the return type declaration makes the return value type stable, so that’s helpful for type stability of the code that calls the function, but it doesn’t help for type stability of the code inside the function.

4 Likes

technically i believe it always adds the convert statement.
Its just that if it is already the right function the convert just does the identity operation

4 Likes

Note that a type declaration makes the return value type of a specific method stable. And Julia does not call methods at some call site, it calls a function with some arguments for the compiler to either dynamic dispatch or to inline the right method during compilation (if there is only one possibility). So, in the end, what will matter is if the compiler can infer that all the methods that could be called from one function at some call point all share the same return type.

4 Likes

Yes that’s right:

struct Foo end
function Base.convert(::Type{Foo}, ::Foo)
    @info "Called convert!"
    Foo()
end
function f()::Foo
    Foo()
end
julia> f()
[ Info: Called convert!
Foo()
4 Likes