# Type annotations with abstract types (or when is \`\<:\` required?)

**URL:** <https://discourse.julialang.org/t/type-annotations-with-abstract-types-or-when-is-required/72364>\
**Category:** General Usage\
**Tags:** type\
**Created:** [December 1, 2021, 12:11pm UTC](https://discourse.julialang.org/t/type-annotations-with-abstract-types-or-when-is-required/72364 "2021-12-01T12:11:06Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![cbrnr](https://avatars.discourse-cdn.com/v4/letter/c/919ad9/32.png) [@cbrnr](https://discourse.julialang.org/u/cbrnr)\
**Post date:** [December 1, 2021, 12:11pm UTC](https://discourse.julialang.org/t/type-annotations-with-abstract-types-or-when-is-required/72364/1 "2021-12-01T12:11:06Z")

</div>

Let’s assume I define a function `f` with two parameters `x` and `n`, where `x` should be a vector of integer numbers and `n` should be an integer. I though that I could use the abstract `Integer` type to write the following function header:

```julia
function f(x::Vector{Integer}, n::Integer)
    x .* n
end

```

However, this gives an error when calling `f([1, 2, 3], 2)`:

```julia
ERROR: MethodError: no method matching f(::Vector{Int64}, ::Int64)
Closest candidates are:
  f(::Vector{Integer}, ::Integer)

```

When I change the type parameter of `Vector` to `<:Integer`, everything works as expected, i.e.

```julia
function f(x::Vector{<:Integer}, n::Integer)
    x .* n
end

```

Intuitively, I expected the abstract type `Integer` to work, because by definition it should accept all its (direct and indirect) subtypes. This is the case for `n::Integer`, but not `x::Vector{Integer}`. What is the reasoning behind this behavior? Where is the error in my thinking that it should work?

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [December 1, 2021, 12:25pm UTC](https://discourse.julialang.org/t/type-annotations-with-abstract-types-or-when-is-required/72364/2 "2021-12-01T12:25:22Z")

</div>

This is described in detail [here](https://docs.julialang.org/en/v1/manual/types/#Parametric-Types) in the Julia Manual. If something is not clear there can you please comment?

---

<div class="post-metadata">

**Author:** ![cbrnr](https://avatars.discourse-cdn.com/v4/letter/c/919ad9/32.png) [@cbrnr](https://discourse.julialang.org/u/cbrnr)\
**Post date:** [December 1, 2021, 12:32pm UTC](https://discourse.julialang.org/t/type-annotations-with-abstract-types-or-when-is-required/72364/3 "2021-12-01T12:32:46Z")

</div>

I read that section multiple times, but I don’t think it explains the problem I’m having. It even contains examples like `Point{AbstractString}`, which conceptually should be `Vector{Integer}` in my example (both `AbstractString` and `Integer` are abstract types) – but this doesn’t work and I need to use `Vector{<:Integer}`.

I think I’m struggling with how to write type annotations and not types. The [UnionAll section](https://docs.julialang.org/en/v1/manual/types/#UnionAll-Types) even mentions the syntax `Array{<:Integer}`, but my question is why the `<:` operator is necessary when `Integer` is already an abstract type.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [December 1, 2021, 12:35pm UTC](https://discourse.julialang.org/t/type-annotations-with-abstract-types-or-when-is-required/72364/4 "2021-12-01T12:35:37Z")

</div>

A superficial explanation that might be easy to remember is that `Integer` is an abstract type, so if you input an integer of type `Int64`, this is a subtype of `Integer` and is therefore a match:

```julia
jl> Int64 <: Integer
true

jl> 3 isa Integer
true

```

But `Vector{Integer}` is _not_ abstract type, it is concrete:

```julia
jl> isconcretetype(Vector{Integer})
true

```

Now, `[1, 2, 3]` has type `Vector{Int64}`. Since concrete types cannot have subtypes, `Vector{Int64}` cannot be a subtype of `Vector{Integer}`, so you don’t get a match:

```julia
jl> Vector{Int64} <: Vector{Integer}
false

```

So why is `Vector{Integer}` not abstract? Well, it can be instantiated, it’s a vector with heterogeneous elements, like `Integer[1, 0x03]`. It’s the same thing with `Vector{Any}`, like `Any[5, sin, "hello"]`. If `Vector{Any}` weren’t concrete, you couldn’t make arbitrary collections like this.

This isn’t really the _reason_ for this choice, there are some type-theoretic explanations that are hard to grasp (for me), but my explanation is what I use to remember this.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [December 1, 2021, 12:38pm UTC](https://discourse.julialang.org/t/type-annotations-with-abstract-types-or-when-is-required/72364/5 "2021-12-01T12:38:49Z")

</div>

> [@cbrnr](#):
>
> I read that section multiple times, but I don’t think it explains the problem I’m having.

maybe this helps: [Vector{Int} \<: Vector{Real} is false??? · JuliaNotes.jl](https://m3g.github.io/JuliaNotes.jl/stable/typevariance/)

In short, `[1,2,3]` is a `Vector{Int64}`, which _cannot_ contain, for instance, an `Int32`. Thus it has a _constraint_ that `Vector{Integer}` does not have. That is why `Vector{Int64}` cannot be used as a subtype of `Vector{Integer}`.

---

<div class="post-metadata">

**Author:** ![digital\_carver](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/digital_carver/32/33818_2.png) [@digital\_carver](https://discourse.julialang.org/u/digital_carver)\
**Post date:** [December 1, 2021, 12:50pm UTC](https://discourse.julialang.org/t/type-annotations-with-abstract-types-or-when-is-required/72364/6 "2021-12-01T12:50:37Z")

</div>

> [@cbrnr](#):
>
> It even contains examples like `Point{AbstractString}` , which conceptually should be `Vector{Integer}` in my example

Note that they use `Point{AbstractString}` to demonstrate `Point{AbstractString} <: Point`, and `Point{AbstractString} <: Pointy{AbstractString}` - which are equivalent here to `Vector{Integer} <: Vector` and `Vector{Integer} <: AbstractArray{Integer}` , both of which are true.

The relevant part for this discussion is

```julia
julia> Point{Float64} <: Point{Real}
false

```

> Warning

> This last point is _very_ important: even though `Float64 <: Real` we **DO NOT** have `Point{Float64} <: Point{Real}` .

It then goes on to explain why this is, and shows an example of how it’s significant for performance reasons.

---

<div class="post-metadata">

**Author:** ![cbrnr](https://avatars.discourse-cdn.com/v4/letter/c/919ad9/32.png) [@cbrnr](https://discourse.julialang.org/u/cbrnr)\
**Post date:** [December 1, 2021, 12:54pm UTC](https://discourse.julialang.org/t/type-annotations-with-abstract-types-or-when-is-required/72364/7 "2021-12-01T12:54:57Z")

</div>

Thank you, these are all really helpful answers ❤! I guess I should have read that section more carefully, because as you point out it is already explained.

---

<div class="post-metadata">

**Author:** ![cbrnr](https://avatars.discourse-cdn.com/v4/letter/c/919ad9/32.png) [@cbrnr](https://discourse.julialang.org/u/cbrnr)\
**Post date:** [December 1, 2021, 12:58pm UTC](https://discourse.julialang.org/t/type-annotations-with-abstract-types-or-when-is-required/72364/8 "2021-12-01T12:58:06Z")

</div>

All three answers by @DNF, @lmiq, and @digital_carver are solutions to my question, so I’m having a hard time marking just one as the solution. I hope this is OK with everyone if I just mark the last answer.
