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)
```

2 Likes

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:
```

3 Likes

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`

.

1 Like