3

Documentation:

Argument-type declarations normally have no impact on performance: regardless of what argument types (if any) are declared, Julia compiles a specialized version of the function for the actual argument types passed by the caller. For example, calling fib(1) will trigger the compilation of specialized version of fib optimized specifically for Int arguments, which is then re-used if fib(7) or fib(15) are called.

The provided example:

fib(n::Integer) = n ≤ 2 ? one(n) : fib(n-1) + fib(n-2)

but then in the Performance Tips:

# This will not specialize:

function f_type(t)  # or t::Type
    x = ones(t, 10)
    return sum(map(sin, x))
end

From my understanding of the performance tips, with or without type annotations fib(b::Integer) or fib(b) shouldn't specialize specifically for Int arguments.

It seems with or without the type annotation no specialization will happen, but why does the manual seem to indicate that it will specialize?

Sundar R
  • 13,776
  • 6
  • 49
  • 76

2 Answers2

1

The example in the Performance Tips page is about the specific case where you pass the type itself as the argument to the function. As the beginning of that section says:

Julia avoids automatically specializing on argument type parameters in three specific cases: Type, Function, and Vararg

f_type in that example is a function that accepts a Type t. A call to that function will look like, for eg., f_type(Int). The section says that type specialization isn't done based on the Int type in this case, where the Int is passed as a value of the parameter itself (and then passed through to another function). (Specifically, the Type isn't specialized into a specific parametrized type like Type{Int}, as it normally would be if the argument wasn't one of the above mentioned three cases.)

This doesn't apply to the fib method (or most methods we normally define). fib accepts a value whose type is (a subtype of) Integer, not the type itself. In such cases, a call like fib(1) or fib(UInt8(2)) does create type-specialized compiled versions of the function.

Sundar R
  • 13,776
  • 6
  • 49
  • 76
  • But is this an exception from the normal rule, or is it that the input `t` is a _value_ of type `DataType`, so `DataType` is what the compiler sees? – DNF Jun 29 '22 at 20:46
  • @DNF I've added a paranthetical to the second paragraph to clarify what's exceptional about this. If we had `f_vec(v::Vector) = sum(v)`, then `f_vec([1, 2, 3])` would cause the compiler to produce a type-parameter specialized method `f_vec(::Vector{Int64})` (and the `.specializations` suggested at the end of that section reports exactly that). But a `f_type(Int)` doesn't cause `f_type(::Type{Int})` to be compiled, only the more generic `f_type(::Type)`. – Sundar R Jun 29 '22 at 23:16
0

In layman words, Julia will always specialize on function arguments either with or without annotation, except in three cases. One of them is when the arguments are passed to another function, since specializing twice will slow compilation down, and it will finally be specialized at the inner function call, so no performance hit occurs.

So, fib(n:Int) is equivalent to fib(n) and both will use a specialized compiled version of the function for the Int64 type unless n is already of a different type than Int64, it will specialize for that type.

AboAmmar
  • 5,439
  • 2
  • 13
  • 24