Both definitions are equivalent. Normally you will use fun(n::Integer)
form and apply fun(n::T) where T<:Integer
only if you need to use specific type T
directly in your code. For example consider the following definitions from Base (all following definitions are also from Base) where it has a natural use:
zero(::Type{T}) where {T<:Number} = convert(T,0)
or
(+)(x::T, y::T) where {T<:BitInteger} = add_int(x, y)
And even if you need type information in many cases it is enough to use typeof
function. Again an example definition is:
oftype(x, y) = convert(typeof(x), y)
Even if you are using a parametric type you can often avoid using where
clause (which is a bit verbose) like in:
median(r::AbstractRange{<:Real}) = mean(r)
because you do not care about the actual value of the parameter in the body of the function.
Now - if you are Julia user like me - the question is how to convince yourself that this works as expected. There are the following methods:
- you can check that one definition overwrites the other in methods table (i.e. after evaluating both definitions only one method is present for this function);
- you can check code generated by both functions using
@code_typed
, @code_warntype
, @code_llvm
or @code_native
etc. and find out that it is the same
- finally you can benchmark the code for performance using
BenchmarkTools
A nice plot explaining what Julia does with your code is here http://slides.com/valentinchuravy/julia-parallelism#/1/1 (I also recommend the whole presentation to any Julia user - it is excellent). And you can see on it that Julia after lowering AST applies type inference step to specialize function call before LLVM codegen step.
You can hint Julia compiler to avoid specialization. This is done using @nospecialize
macro on Julia 0.7 (it is only a hint though).