# Why isn't \`Vector{\<:Float64}\` reduced to \`Vector{Float64}\`?

**URL:** <https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555>\
**Category:** General Usage\
**Tags:** type, parametric-types\
**Created:** [July 28, 2024, 12:49am UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555 "2024-07-28T00:49:44Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![frankwswang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frankwswang/32/18561_2.png) [@frankwswang](https://discourse.julialang.org/u/frankwswang)\
**Post date:** [July 28, 2024, 12:49am UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/1 "2024-07-28T00:49:44Z")

</div>

I’m not sure if I misremembered, but I thought when applying `<:` to a type parameter that represents a concrete type, `<:` would automatically be removed.

However, it seems that in Julia 1.10 and 1.11, that’s not the case, and `Vector{<:Float64}` and `Vector{Float64}` are not equivalent to each other.

```julia
julia> t1 = Vector{<:Float64}
Vector{<:Float64} (alias for Array{<:Float64, 1})

julia> t2 = Vector{Float64}
Vector{Float64} (alias for Array{Float64, 1})

julia> t2 <: t1
true

julia> t1 <: t2
false

```

Is there a reason for `t1` and `t2` not to be considered identical?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [July 28, 2024, 12:54am UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/2 "2024-07-28T00:54:19Z")

</div>

This is in the [Julia FAQ](https://docs.julialang.org/en/v1/manual/faq/#Troubleshooting-%22method-not-matched%22:-parametric-type-invariance-and-MethodErrors). There are many discussions that try to help explain this. See e.g.

- [Problem with Complex{Rationals} - #7 by stevengj](https://discourse.julialang.org/t/problem-with-complex-rationals/9474/7)
- [Why [1, 2, 3] is not a Vector{Number}? - #19 by stevengj](https://discourse.julialang.org/t/why-1-2-3-is-not-a-vector-number/52645/19)
- [Why [1, 2, 3] is not a Vector{Number}? - #28 by StefanKarpinski](https://discourse.julialang.org/t/why-1-2-3-is-not-a-vector-number/52645/28)

~~I guess you are asking specifically about `Vector{<:Float64}`. Realize that `Vector{<:T}` for _any_ type `T` is a _set_ of types: `Vector` types for any subtype of `T`. Now, I guess your point is that, since `Float64` is concrete, it has exactly one subtype `Float64`, so `Vector{<:Float64}` is a **set containing only one element** , `Vector{Float64}`. Still, in mathematics we generally don’t equate a set of a single element with that element: \{x\} \ne x.~~ As noted by @nsajko below, the bottom type `Union{}` is a subtype of `Float64`, so `Vector{Union{}} <: Vector{<:Float64}`.

---

<div class="post-metadata">

**Author:** ![frankwswang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frankwswang/32/18561_2.png) [@frankwswang](https://discourse.julialang.org/u/frankwswang)\
**Post date:** [July 28, 2024, 1:01am UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/3 "2024-07-28T01:01:26Z")

</div>

I am aware that `Vector{T1}` is not a subtype of `Vector{T2}` even if `T1 <: T2`… I am talking about the the specific case where `T2` is a concrete type so it has no subtypes except itself.

In that case, one would assume `Vector{<:T2}` (a.k.a. Vector{T} where {T\<:T2}) falls back to `Vector{T2}`.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [July 28, 2024, 1:02am UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/4 "2024-07-28T01:02:33Z")

</div>

> [@frankwswang](#):
>
> I am talking about the the specific case where `T2` is a concrete type so it has no subtypes except itself.

~~Yes, I edited my post already to address that point. As I said, you are asking Julia to equate a set containing only one element with that element. They are certainly related, but it would not be normal in mathematics to equate the two.~~ As noted by @nsajko below, the bottom type `Union{}` is a subtype of `Float64`, so `Vector{Union{}} <: Vector{<:Float64}`.

(That being said, there are other places in Julia that _do_ blur this distinction. e.g. `Union{Float64} == Float64 == Union{<:Float64}`: the `Union` operation acts sort of like set union, but it seems to equate concrete types `T` with sets \{ T \}. Not doing this would be pretty inconvenient, though — instead of `Union{Float32, Float64}`, I guess you’d need to write something like `Union{<:Float32, <:Float64}`, which would make some pedantic sense but would annoy everyone in practice.)

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 28, 2024, 7:36am UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/5 "2024-07-28T07:36:02Z")

</div>

> [@frankwswang](#):
>
> talking about the the specific case where `T2` is a concrete type so it has no subtypes except itself

Counterexample:

```julia-repl
julia> Union{} <: Float64
true

```

Indeed, then we have:

```julia-repl
julia> Vector{Union{}} <: Vector{<:Float64}
true

```

Don’t forget about the bottom type!

---

<div class="post-metadata">

**Author:** ![cjdoris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cjdoris/32/213133_2.png) [@cjdoris](https://discourse.julialang.org/u/cjdoris)\
**Post date:** [July 28, 2024, 7:36am UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/6 "2024-07-28T07:36:58Z")

</div>

> [@frankwswang](#):
>
> However, it seems that in Julia 1.10 and 1.11, that’s not the case, and `Vector{<:Float64}` and `Vector{Float64}` are not equivalent to each other.

They aren’t the same thing because `Vector{Union{}}` is also a subtype of `Vector{<:Float64}`.

---

<div class="post-metadata">

**Author:** ![frankwswang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frankwswang/32/18561_2.png) [@frankwswang](https://discourse.julialang.org/u/frankwswang)\
**Post date:** [July 28, 2024, 8:05pm UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/8 "2024-07-28T20:05:34Z")

</div>

This is very interesting. I guess it makes sense to define a “bottom type” with respect to `Any` as the “top type” for the entire type system. On the other hand, it seems that `Union{}` is not intended to be revealed to the user:

```julia
julia> subtypes(Float64)
Type[]

```

Anyway, thank you all for the comments that helped me deepen my understanding of Julia’s type system.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 28, 2024, 8:45pm UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/9 "2024-07-28T20:45:13Z")

</div>

> [@frankwswang](#):
>
> a “bottom type”

Its doc string is here: [`Union{}`](https://docs.julialang.org/en/v1/base/base/#Union%7B%7D).

But definitely take a look at the subtype operator’s (`<:`) doc string, too. The in-development version of the doc string, specifically: [`<:`](https://docs.julialang.org/en/v1.12-dev/base/base/#Core.:%3C:)

---

<div class="post-metadata">

**Author:** ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)\
**Post date:** [July 28, 2024, 9:24pm UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/10 "2024-07-28T21:24:44Z")

</div>

If I understand correctly, `Vector{<:Float64}` and `Vector{Float64}` cannot differ in terms of the values they can contain (since there are no values of type `Union{}`).

Couldn’t the compiler just replace `Vector{<:Float64}` with `Vector{Float64}` ?

Also related question: Is there any difference in how `Vector{<:Float64}` and `Vector{Float64}` are stored in memory?

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [July 28, 2024, 9:37pm UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/11 "2024-07-28T21:37:15Z")

</div>

> [@e3c6](#):
>
> Is there any difference in how `Vector{<:Float64}` and `Vector{Float64}` are stored in memory?

`Vector{<:Float64}` is an abstract type, so it doesn’t have any instances and hence no memory layout. It has two subtypes: `Vector{Float64}` and `Vector{Union{}}`, both of which can be instantiated, although the latter only has a single possible value, namely the empty vector `Union{}[]`.

So in practical terms, I suppose that’s the most important distinction: `Union{}[] isa Vector{<:Float64}` but `!(Union{}[] isa Vector{Float64})`.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 28, 2024, 9:45pm UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/12 "2024-07-28T21:45:53Z")

</div>

> [@nsajko](#):
>
> It’s doc string is here: [`Union{}`](https://docs.julialang.org/en/v1/base/base/#Union%7B%7D).

Made a PR to expand the doc string:

> <https://github.com/JuliaLang/julia/pull/55291>
>
> Give some characterizations/relevant terms from type theory.
> 
> Clarify the, pre…viously unexplained, usage of "bottom" in names. Cross-reference the subtyping doc string.
> 
> Add an entry to the doctest, clarifying the last sentence.

Also:

> <https://github.com/JuliaLang/julia/pull/55293>
>
> Having it is unnecessary, given \`Union{}\`, and confusing, now that \`Top\` is gone….
> 
> Fixes #55292

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 28, 2024, 9:48pm UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/13 "2024-07-28T21:48:02Z")

</div>

> [@danielwe](#):
>
> although the latter only has a single possible value, namely the empty vector `Union{}[]`.

Counterexample:

```julia-repl
julia> Vector{Union{}}(undef, 2)
2-element Vector{Union{}}:
 #undef
 #undef

julia> Vector{Union{}}(undef, 1)
1-element Vector{Union{}}:
 #undef

```

So it can’t have elements (throws on access to any index), but, confusingly, it _can_ have a nonzero length.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [July 28, 2024, 9:53pm UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/14 "2024-07-28T21:53:18Z")

</div>

I think it would potentially be interesting for us to have a rule that a type is not instantiable if it contains a field with an uninhabited type, but enforcing that rule consistently would be very tricky.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 28, 2024, 10:02pm UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/15 "2024-07-28T22:02:56Z")

</div>

> [@Oscar\_Smith](#):
>
> I think it would potentially be interesting for us to have a rule that a type is not instantiable if it contains a field with an uninhabited type

Wouldn’t that be quite breaking? AFAIK some parts of the ecosystem, due to @tkf as far as I remember, but still very relevant, use a pattern of starting from an empty collection of `Union{}` element type, then adding elements one-by-one, progressively widening the element type.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [July 28, 2024, 10:14pm UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/16 "2024-07-28T22:14:40Z")

</div>

An empty `Array{Union}` doesn’t have uninhabitable fields. It’s only ones of size\>0 that do. That probably does make this hard to implement though…

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 28, 2024, 10:17pm UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/17 "2024-07-28T22:17:53Z")

</div>

> [@Oscar\_Smith](#):
>
> only ones of size\>0

Once upon a time I, too, suggested these should be unconstructible, but it was shot down pretty hard:

> <https://github.com/JuliaLang/julia/issues/53002>
>
> \`\`\`julia
> julia\> Vector{Union{}}(undef, 1)
> 1-element Vector{Union{}}:
> #undef
> …
> \`\`\`
> 
> Two issues:
> 
> 1. an array of type \`\<:AbstractArray{Union{}}\` must always be empty (because \`Union{}\` never has instances). So why is the object being \`show\`-n as "\`1-element Vector{Union{}}\`"?
> 
> 2. Given that \`\<:AbstractArray{Union{}}\` can never have elements (or, more precisely I guess, \`iterate\` will either return \`nothing\` or throw), trying to construct such an array with a nonzero length should throw.
> 
> The example above is by @tpapp in https://github.com/JuliaLang/julia/issues/52385#issuecomment-1903922191

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [July 28, 2024, 10:25pm UTC](https://discourse.julialang.org/t/why-isnt-vector-float64-reduced-to-vector-float64/117555/18 "2024-07-28T22:25:38Z")

</div>

> [@nsajko](#):
>
> So it can’t have elements (throws on access to any index), but, confusingly, it _can_ have a length.

Interesting, thanks for the correction!
