This what I think about the subject:
I think that for functions with only one argument those two manners to define the type are equivalent, although the second one ( with where {T<:Real}
), is more convenient when you have to use the type of the input in the body of the function. For example, the two functions produce the exact same machine code:
julia> function f(x::Real)
y = zero(eltype(x))
for i=1:div(x,2)
y += i
end
end
f (generic function with 1 method)
julia> function g(x::T) where T<:Real
y = zero(T)
for i=1:div(x,2)
y += i
end
end
g (generic function with 1 method)
julia> @code_native f(10)
.section __TEXT,__text,regular,pure_instructions
Filename: REPL[1]
pushq %rbp
movq %rsp, %rbp
Source line: 4
popq %rbp
retq
nopw %cs:(%rax,%rax)
julia> @code_native g(10)
.section __TEXT,__text,regular,pure_instructions
Filename: REPL[2]
pushq %rbp
movq %rsp, %rbp
Source line: 4
popq %rbp
retq
nopw %cs:(%rax,%rax)
julia> @code_native f(10.)
.section __TEXT,__text,regular,pure_instructions
Filename: REPL[1]
pushq %rbp
movq %rsp, %rbp
Source line: 3
subq $64, %rsp
vmovsd %xmm0, -8(%rbp)
movabsq $4665565568, %rax ## imm = 0x11616E180
vmovsd (%rax), %xmm1 ## xmm1 = mem[0],zero
movabsq $fmod, %rax
callq *%rax
vmovsd -8(%rbp), %xmm1 ## xmm1 = mem[0],zero
vsubsd %xmm0, %xmm1, %xmm0
movabsq $4665565576, %rax ## imm = 0x11616E188
vmulsd (%rax), %xmm0, %xmm0
vroundsd $4, %xmm0, %xmm0, %xmm2
movabsq $colon, %rax
movabsq $4665565584, %rcx ## imm = 0x11616E190
vmovsd (%rcx), %xmm0 ## xmm0 = mem[0],zero
leaq -56(%rbp), %rdi
vmovapd %xmm0, %xmm1
callq *%rax
xorl %eax, %eax
movq -24(%rbp), %rcx
nopl (%rax)
L112:
addq $1, %rax
cmpq %rax, %rcx
jge L112
Source line: 4
addq $64, %rsp
popq %rbp
retq
nop
julia> @code_native g(10.)
.section __TEXT,__text,regular,pure_instructions
Filename: REPL[2]
pushq %rbp
movq %rsp, %rbp
Source line: 3
subq $64, %rsp
vmovsd %xmm0, -8(%rbp)
movabsq $4665570672, %rax ## imm = 0x11616F570
vmovsd (%rax), %xmm1 ## xmm1 = mem[0],zero
movabsq $fmod, %rax
callq *%rax
vmovsd -8(%rbp), %xmm1 ## xmm1 = mem[0],zero
vsubsd %xmm0, %xmm1, %xmm0
movabsq $4665570680, %rax ## imm = 0x11616F578
vmulsd (%rax), %xmm0, %xmm0
vroundsd $4, %xmm0, %xmm0, %xmm2
movabsq $colon, %rax
movabsq $4665570688, %rcx ## imm = 0x11616F580
vmovsd (%rcx), %xmm0 ## xmm0 = mem[0],zero
leaq -56(%rbp), %rdi
vmovapd %xmm0, %xmm1
callq *%rax
xorl %eax, %eax
movq -24(%rbp), %rcx
nopl (%rax)
L112:
addq $1, %rax
cmpq %rax, %rcx
jge L112
Source line: 4
addq $64, %rsp
popq %rbp
retq
nop
Now, when you have more than one input, there where
syntax allows you to be more restrictive on the input of your function. For example:
julia> f(x::Real,y::Real) = x + y
f (generic function with 2 methods)
julia> g(x::T,y::T) where {T<:Real} = x + y
g (generic function with 2 methods)
julia> f(1,1.)
2.0
julia> g(1,1.)
ERROR: MethodError: no method matching g(::Int64, ::Float64)
Closest candidates are:
g(::T<:Real) where T<:Real at REPL[2]:2
g(::T<:Real, ::T<:Real) where T<:Real at REPL[8]:1
julia> g(1,1)
2
julia> f(1,1)
2
With the where
syntax you are able to enforce that both x
and y
must have the same concrete type.