Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between `where` keyword inside or outside the curly braces

What is the difference between

function foo(a::Adjoint{Float64, Matrix{T}} where T)
    return 0
end

and

function foo(a::Adjoint{Float64, Matrix{T} where T})
    return 1
end

(Note the location of the curly braces.)

julia> methods(foo)
# 2 methods for generic function "foo":
[1] foo(a::Adjoint{Float64,Array{T,2}} where T) in Main at REPL[247]:2
[2] foo(a::Adjoint{Float64,Array{T,2} where T}) in Main at REPL[248]:2

It seems in both cases the function would accept an adjoint of Matrix of type T? I can't figure out what the difference between the two functions is.

like image 833
miha priimek Avatar asked Jul 20 '20 12:07

miha priimek


2 Answers

The first is a unionall type, the second is a concrete type:

julia> isconcretetype(Adjoint{Float64, Matrix{T} where T})
true

julia> isconcretetype(Adjoint{Float64, Matrix{T}} where T)
false

julia> (Adjoint{Float64, Matrix{T}} where T) isa Core.UnionAll
true

The first one is the infinite set of adjoints wrapping a Matrix of some type. In other words, we could imagine representing the infinite set in pseudocode with something like:

Set([Adjoint{Float64, T} for T in all_possible_types])

Whereas the second is an adjoint wrapping a Matrix of some type, or in other words:

Adjoint{Float64, Matrix_of_any_type}.

You almost always want the former, not the latter. There is little reason to construct an adjoint which can contain any Matrix, usually you just want an adjoint with one type.

The difference is clearer with Vector:

  • Vector{Vector{T}} where T is a unionall representing all vector of same-type vectors.
  • Vector{Vector{T} where T} is a vector containing the specific element type Vector{T} where T.
like image 53
Jakob Nissen Avatar answered Oct 19 '22 05:10

Jakob Nissen


Here is an example that illustrates the difference, for the simpler case of Vector{Vector{T} where T} vs Vector{Vector{T}} where T.

First make some type aliases:

julia> const InsideWhere = Vector{Vector{T} where T}
Array{Array{T,1} where T,1}

julia> const OutsideWhere = Vector{Vector{T}} where T
Array{Array{T,1},1} where T

The default array constructor promotes elements to a common type if possible:

julia> x = [[1, 2], [1.2, 3.4]]
2-element Array{Array{Float64,1},1}:
 [1.0, 2.0]
 [1.2, 3.4]

julia> x isa InsideWhere
false

julia> x isa OutsideWhere
true

But by using a typed array literal we can avoid the automatic promotion:

julia> y = ( Vector{T} where T )[[1, 2], [1.2, 3.4]]
2-element Array{Array{T,1} where T,1}:
 [1, 2]
 [1.2, 3.4]

julia> y isa InsideWhere
true

julia> y isa OutsideWhere
false
like image 4
Cameron Bieganek Avatar answered Oct 19 '22 04:10

Cameron Bieganek