# Question about function argument

**URL:** <https://discourse.julialang.org/t/question-about-function-argument/7420>\
**Category:** New to Julia\
**Created:** [November 30, 2017, 8:58pm UTC](https://discourse.julialang.org/t/question-about-function-argument/7420 "2017-11-30T20:58:38Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![jianghaizhu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jianghaizhu/32/1866_2.png) [@jianghaizhu](https://discourse.julialang.org/u/jianghaizhu)\
**Post date:** [November 30, 2017, 8:58pm UTC](https://discourse.julialang.org/t/question-about-function-argument/7420/1 "2017-11-30T20:58:38Z")

</div>

I have a question about the function argument types. Here is my example.

```julia
julia> r = [(0, 0), (0, 0)]
2-element Array{Tuple{Int64,Int64},1}:
 (0, 0)
 (0, 0)

julia> f1(r::Vector{NTuple{2}}) = length(r)
f1 (generic function with 1 method)

julia> f2(r::Vector{NTuple{2, <:Real}}) = length(r)
f2 (generic function with 1 method)

julia> f3(r::Vector{NTuple{2, T}}) where {T<:Real} = length(r)
f3 (generic function with 1 method)

julia> f1(r)
ERROR: MethodError: no method matching f1(::Array{Tuple{Int64,Int64},1})
Closest candidates are:
  f1(::Array{Tuple{T,T} where T,1}) at REPL[38]:1

julia> f2(r)
ERROR: MethodError: no method matching f2(::Array{Tuple{Int64,Int64},1})
Closest candidates are:
  f2(::Array{Tuple{#s16,#s16} where #s16<:Real,1}) at REPL[39]:1

julia> f3(r)
2

```

My question is why `f1` and `f2` didn’t work and how are these three functions different? Thanks!

---

<div class="post-metadata">

**Author:** ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)\
**Post date:** [November 30, 2017, 9:37pm UTC](https://discourse.julialang.org/t/question-about-function-argument/7420/2 "2017-11-30T21:37:43Z")

</div>

You are hitting invariance. Have a read through this [https://docs.julialang.org/en/stable/manual/types/#Parametric-Composite-Types-1](https://docs.julialang.org/en/stable/manual/types/#Parametric-Composite-Types-1) and report back if you’re still confused (likely).

---

<div class="post-metadata">

**Author:** ![dfdx](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dfdx/32/120_2.png) [@dfdx](https://discourse.julialang.org/u/dfdx)\
**Post date:** [November 30, 2017, 9:38pm UTC](https://discourse.julialang.org/t/question-about-function-argument/7420/3 "2017-11-30T21:38:17Z")

</div>

Also try this:

```julia
julia> f2(r::Vector{<:NTuple{2, Real}}) = length(r)
f2 (generic function with 1 method)

julia> f2(r)
2

```

---

<div class="post-metadata">

**Author:** ![raminammour](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raminammour/32/13572_2.png) [@raminammour](https://discourse.julialang.org/u/raminammour)\
**Post date:** [November 30, 2017, 9:57pm UTC](https://discourse.julialang.org/t/question-about-function-argument/7420/4 "2017-11-30T21:57:30Z")

</div>

I am sure someone else can do a better job, but here is my attempt.

First you can find out what works and what doesn’t by doing:

```julia
julia> typeof(r)<: Array{Tuple{s1,s1},1} where s1<:Real
true

julia> typeof(r)<: Array{Tuple{s1,s1} where s1<:Real,1}
false

julia> typeof(r)<: Array{Tuple{T,T} where T,1}
false

```

This is explained as _type invariance_ in the docs:  
[https://docs.julialang.org/en/stable/manual/types/](https://docs.julialang.org/en/stable/manual/types/)

For `f2` the input is mainly a vector of pointers that can hold `Real`, and `f1` is a a vector of pointers that hold anything. Because the parameters vary inside the `{}`. For `f3` the type has to be the same (outside the `{}`), and can be inferred statically to be `Int64` in this case so it works.

Examples:

```julia
julia> bla=Array{Tuple{T,T} where T}(2)
2-element Array{Tuple{T,T} where T,1}:
 #undef
 #undef

julia> bla[1]=r[1];bla[2]=("cat","dog")
("cat", "dog")
julia> f1(bla)
2

```

Hope this helps.

---

<div class="post-metadata">

**Author:** ![jianghaizhu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jianghaizhu/32/1866_2.png) [@jianghaizhu](https://discourse.julialang.org/u/jianghaizhu)\
**Post date:** [December 1, 2017, 2:57pm UTC](https://discourse.julialang.org/t/question-about-function-argument/7420/5 "2017-12-01T14:57:11Z")

</div>

Thanks a lot for all your answers. I read the manual before and read it again last night. I think I learnt a lot more.

I understood before that the position of `where` keyword affects the scope of the type variables. In `Vector{NTuple{2, T} where T}`, the `T` is local and cannot be seen outside of `Vector{}` and `T` can change from `Tuple` to `Tuple` in the `Vector`, whereas in `Vector{NTuple{2, T}} where T`, the `T` can be accessed in the method and all `Tuple` in the `Vector` must have the same element type `T`. What I didn’t know is that the first one declares a concrete type and the second declares an abstract type. That explains why `f1` and `f2` didn’t work because `Array{Tuple{Int64,Int64},1}` is a concrete type and cannot be a subtype of another concrete type.

This all makes sense now except I still don’t understand why `Vector{NTuple{2, T} where T}` declares a concrete type and `Vector{NTuple{2, T}} where T` declares an abstract type. Is this just by definition? or is there some reasoning behind this behavior? If so, what is the reasoning? Thanks!

---

<div class="post-metadata">

**Author:** ![jianghaizhu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jianghaizhu/32/1866_2.png) [@jianghaizhu](https://discourse.julialang.org/u/jianghaizhu)\
**Post date:** [December 1, 2017, 3:08pm UTC](https://discourse.julialang.org/t/question-about-function-argument/7420/6 "2017-12-01T15:08:31Z")

</div>

```julia
julia> f2(r::Vector{<:NTuple{2, Real}}) = length(r) 
f2 (generic function with 1 method)

```

Thanks for this wonderful example. After carefully reading the manual, I realize this is `covariant` type and also unlike other types, `Tuple` types are `covariant` as well , so `Tuple{2, Real}` is an abstract type. `Vector{<:NTuple{2, Real}}` is the same as `Vector{T} where T<:NTuple{2, Real}` and `Tuple{Int64,Int64}` is a subtype of `NTuple{2, Real}`. That is why your example works.

---

<div class="post-metadata">

**Author:** ![yurivish](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yurivish/32/307_2.png) [@yurivish](https://discourse.julialang.org/u/yurivish)\
**Post date:** [December 6, 2017, 1:53am UTC](https://discourse.julialang.org/t/question-about-function-argument/7420/7 "2017-12-06T01:53:05Z")

</div>

> [@jianghaizhu](#):
>
> This all makes sense now except I still don’t understand why Vector{NTuple{2, T} where T} declares a concrete type and Vector{NTuple{2, T}} where T declares an abstract type. Is this just by definition? or is there some reasoning behind this behavior? If so, what is the reasoning? Thanks!

One way to understand it is to think about what an abstract type _is_ – in Julia, it’s a type that cannot be instantiated, and potentially has many concrete subtypes.

For example, `Real` (representing a real number) is an abstract type; you can’t instantiate one, and it has many concrete subtypes – among them `Float32`, `Float64`, `Rational`:

```julia
julia> 0.5
0.5

julia> typeof(0.5)
Float64

julia> 1 // 2
1//2

julia> typeof(1 // 2)
Rational{Int64}

julia> Float64 <: Real
true

julia> Rational{Int64} <: Real
true

```

Now, here’s the trick – the type `Real` is the same exact type as the type `T where T <: Real`: they both specify precisely the same set of concrete types. You can see this simplification at the REPL:

```juila
julia> T where T <: Real
Real

```

With a parametric type like `Vector` the same kind of logic applies – `Vector{T where T <: Real}` is the same as `Vector{Real}` and is the _concrete type_ of a list that contains real numbers of any kind:

```julia
julia> v = Vector{Real}()
0-element Array{Real,1}

julia> push!(v, 1.0, 1//2)
2-element Array{Real,1}:
  1.0
 1//2

```

In contrast, the type `Vector{T} where T <: Real`, or `Vector{<:Real}` for short, cannot be concrete because it has _many subtypes_, one for each concrete subtype of `Real`:

```julia
julia> Vector{Float64} <: (Vector{T} where T <: Real)
true

julia> Vector{Rational} <: (Vector{T} where T <: Real)
true

# and many more...

```

---

<div class="post-metadata">

**Author:** ![jianghaizhu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jianghaizhu/32/1866_2.png) [@jianghaizhu](https://discourse.julialang.org/u/jianghaizhu)\
**Post date:** [December 6, 2017, 2:50pm UTC](https://discourse.julialang.org/t/question-about-function-argument/7420/8 "2017-12-06T14:50:54Z")

</div>

Thanks for the explanation! It is very helpful. To complete your example.

```julia
julia> Vector{<:Real}()
ERROR: MethodError: no method matching Array{#s17,1} where #s17<:Real()

```

`Vector{<:Real}` cannot be instantiated.
