1
votes

Following up from a question I posted earlier, I am trying to understand the details of type parameter scope in function methods.
For example:

f(x::Vector{<:Number}) = sum(x)
g(x::Vector{T}) where T<:Number = sum(x)

The <:Number constraint covers only the argument list of f:

julia> methods(f)
f(x::Array{#s1,1} where #s1<:Number)

but it seems that g is parameterized by it:

julia> methods(g)
g(x::Array{T,1}) where T<:Number

Is there a reason why "[y]ou generally want T to cover as little of the signature as possible" aside from style and limiting T's scope?
Are there any implications performance, dispatch, or code-generation wise?

2

2 Answers

4
votes

Indeed f and g above are equivalent as Michael noted. You can dynamically check it by writing:

julia> f(x::Vector{<:Number}) = sum(x)
f (generic function with 1 method)

julia> f(x::Vector{T}) where T<:Number = sum(x)
f (generic function with 1 method)

julia> methods(f)
# 1 method for generic function "f":
[1] f(x::Array{T,1}) where T<:Number in Main at REPL[2]:1

And Julia tells you that the method definition was overwritten (so that it was deemed to be equivalent).

However, in general scoping does matter. See this example:

julia> f(::Vector{Vector{<:Real}}) = "inner"
f (generic function with 1 method)

julia> f(::Vector{Vector{T}}) where {T<:Real}= "outer"
f (generic function with 2 methods)

julia> f(::Any) = "all else"
f (generic function with 3 methods)

julia> methods(f)
# 3 methods for generic function "f":
[1] f(::Array{Array{#s1,1} where #s1<:Real,1}) in Main at REPL[1]:1
[2] f(::Array{Array{T,1},1}) where T<:Real in Main at REPL[2]:1
[3] f(::Any) in Main at REPL[3]:1

julia> f([[1]])
"outer"

julia> f(Vector{<:Real}[[1]])
"inner"

julia> f([Any[1]])
"all else"

With regards to the performance in normal (i.e. type stable) code Julia performs static method dispatch so this should not matter. Probably you could design a contrived example requiring a complex dynamic method dispatch or dynamic code generation where this might matter (but for practical reasons this should not be relevant - just use the specification that represents your needs).

1
votes

The f and g syntaxes are identical, so no difference.