The answer strongly depends on the context the type annotation is used in.
Function signatures
Annotating argument type makes no performance difference, but adds dispatch methods. The general recommendation is to use concrete types in function signatures only for dispatch, and use a possibly loose type bounds otherwise to keep the functions generic. In translating code from Fortran, I’d recommend using Integer
and Real
type annotations for the beginning to easier keep track what is what.
Variable declaration within functions
Usually type declaration is redundant but you need to watch for type stability for performance. Sometimes, a nudge to the type inference algorithm may be useful, though. For performance, the types must be concrete or small unions.
Structure type members
Concrete types are absolutely crucial for performance.
Type parameters / generics
The advises on how to annotate function argument types and local variable types are contradictory. So, you may go without any type annotations for local variables (what’s usually done anyways) or, if you feel uneasy about it, you could use types as parameters in signatures and function body (if you continue using Julia, you’ll need to learn it in any case, so this is just one of many examples)
# Bad: input type is too tight
function cube(x::Float64)
local square::Float64 = x * x
return square * x
end
# Better but local variable type is too loose.
# Does not help with type instabilities within the abstract type
function cube(x::Number)
local square::Number = x * x
return square * x
end
# Good: concrete type is parameterized.
# Function is now generic, and all local variable types are concrete.
# A drawback, of course, is that {T<:Number} is also too tight
# (it could include matrices, rotations, etc)
function cube(x::T) where {T<:Number}
local square::T = x * x
return square * x
end