Can anyone tell me why this code doesn’t compile:
function f1( x::T ) where {T}
function f2( y::U ) where {U <: AbstractVector{T}}
return 0.0
end
return f2
end
Can anyone tell me why this code doesn’t compile:
function f1( x::T ) where {T}
function f2( y::U ) where {U <: AbstractVector{T}}
return 0.0
end
return f2
end
I think you also need to parameterize the T inside:
julia> function f1( x::T ) where {T}
function f2( y::U ) where {U <: AbstractVector{T}} where T
return 0.0
end
return f2
end
f1 (generic function with 1 method)
It depends on what @atteson was hoping to accomplish. I read the code as an attempt to force the element type of the AbstractVector y
to be the same as the type of the argument passed into f1
.
If that was the intent then adding the second where T
won’t work since T gets bound to a different type in f2:
julia> function f1( x::T ) where {T}
function f2( y::U ) where {U <: AbstractVector{T}} where T
return 0.0
end
return f2
end
f1 (generic function with 1 method)
julia> a = f1(1.0)
(::var"#f2#12") (generic function with 1 method)
julia> a(["this","that"])
0.0
This alternative forces the element type of y
to be the same as the type of the argument to f1:
julia> function f1(x::T ) where {T}
function f2(y::AbstractVector{T})
return 0.0
end
return f2
end
f1 (generic function with 1 method)
julia> a = f1(1.0)
(::var"#f2#11"{Float64}) (generic function with 1 method)
julia> a([1.0,2.0])
0.0
julia> a([1,2])
ERROR: MethodError: no method matching (::var"#f2#11"{Float64})(::Vector{Int64})
Closest candidates are:
(::var"#f2#11"{T})(::AbstractVector{T}) where T at REPL[24]:2
Stacktrace:
[1] top-level scope
@ REPL[27]:clock130:
Thank you. That is my intention. Let me change the problem to why the following doesn’t compile. In this case, doing what you suggest would, in my experience, lead to potential type instability since the code wouldn’t be compiled for each possible type of of AbstractVector{T}.
function f1( x::T ) where {T}
function f2( y::AbstractVector{U} ) where {U <: AbstractVector{T}}
return 0.0
end
return f2
end
What failed is the method definition, not compilation (which happens upon function call).
You should also know that in Julia, nested methods like f2
aren’t defined each time outer methods like f1
are called. They’re both defined at the same time, it’s more like the inner one is also implemented with a hidden struct is instantiated at each call of f1
to “capture” f1
variables, look up “functors” in the docs. However, captured variables must be in the method body, not the header type annotations, hence your original UndefVarError: T not defined
for f2
.
This however is perfectly legal and doesn’t need to be nested to capture any variables at all. Think of f3
’s T as a variable that is inferred from the argument y
at method call, and f3
is compiled for every type of T
(and U
).
julia> function f3( y::AbstractVector{U} ) where {T, U <: AbstractVector{T}}
return T, U, typeof(y)
end
where {T, U <: AbstractVector{T}}
is equivalent to where {U <: AbstractVector{T}} where T
, so like @brianguenter said, adding the extra where T
to f2
actually does the same thing as f3
, meaning the T
for f2
is different from the T
for f1
.