# Subtyping directly in parametrics Types

**URL:** <https://discourse.julialang.org/t/subtyping-directly-in-parametrics-types/129949>\
**Category:** New to Julia\
**Created:** [June 17, 2025, 12:16am UTC](https://discourse.julialang.org/t/subtyping-directly-in-parametrics-types/129949 "2025-06-17T00:16:44Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![eotero](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eotero/32/36642_2.png) [@eotero](https://discourse.julialang.org/u/eotero)\
**Post date:** [June 17, 2025, 12:16am UTC](https://discourse.julialang.org/t/subtyping-directly-in-parametrics-types/129949/1 "2025-06-17T00:16:44Z")

</div>

![image](https://global.discourse-cdn.com/julialang/original/3X/8/4/84fae433f3bf0f0c1ae5da805d7183a1d27829b4.png)

Can you explain how I should understand?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 17, 2025, 1:00am UTC](https://discourse.julialang.org/t/subtyping-directly-in-parametrics-types/129949/2 "2025-06-17T01:00:45Z")

</div>

Ignoring the `Vector` part first, `Union{Missing, <:Real}` is an iterated union of unions. It is equal (`==`) to the full form `Union{Missing, T} where T <: Real` and the simplified `Union{Missing, Real}`. That’s just how unions of unions simplify to a union, and sometimes Julia will do that simplification automatically so watch out for apparent discrepancies like this:

```julia
julia> Union{Union{Missing, <:Real}, Integer}
Union{Missing, Real}

```

`Vector{Union{Missing, Real}}` is a concrete type with an abstract type parameter, and a concrete type cannot be subtyped. `Vector{Union{Missing, T}} where T <: Real` is an iterated union of an infinite number of concrete `Vector` types, including `Vector{Union{Missing, Int64}}` and `Vector{Union{Missing, Real}}`. Iterated unions are abstract types, and abstract types can be subtyped.

---

<div class="post-metadata">

**Author:** ![eotero](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eotero/32/36642_2.png) [@eotero](https://discourse.julialang.org/u/eotero)\
**Post date:** [June 17, 2025, 1:23am UTC](https://discourse.julialang.org/t/subtyping-directly-in-parametrics-types/129949/3 "2025-06-17T01:23:06Z")

</div>

` <:Union{Missing,Real}` also works. Documentation should have some particular explanation for this type of use.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 17, 2025, 1:33am UTC](https://discourse.julialang.org/t/subtyping-directly-in-parametrics-types/129949/4 "2025-06-17T01:33:00Z")

</div>

I don’t think the equivalency of unions of unions to a simpler union is documented, and it’s hard to find a good way to explain that. In simpler cases it’s like set theory, but not everything is that simple. In practice, it’s more readable to write down flat unions instead of nesting them.

The inability of concrete types to subtype each other is documented in the introduction of the Types section of the Manual, and the invariance of type parameters (in short, `T<:U` does not imply `V{T}<:V{U}`) and superficial covariance of iterated unions (`T<:U` does imply `V{T} <: V{<:U}`) is documented in the Parametric Types subsection.

It also occurs to me that you might have had a wrong expectation of the `V{<:U}` shorthand for `V{X} where {X<:U}`. Visually, if you just placed the where clause into the curly braces, you might have thought

```julia
Vector{Union{Missing, T}} where T <: Real

```

becomes

```julia
Vector{Union{Missing, <:Real}}

```

but the shorthand can only work across 1 layer of curly braces, not 2. This attempt made an entirely different type, which we can see if we go back the other way across 1 layer of curly braces:

```julia
Vector{Union{Missing, U} where U <: Real}

```

As far as I know, there is no shorthand version of the first type. That’s why the shorthand is only a shorthand, not the primary syntax.

---

<div class="post-metadata">

**Author:** ![eotero](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eotero/32/36642_2.png) [@eotero](https://discourse.julialang.org/u/eotero)\
**Post date:** [June 17, 2025, 7:59pm UTC](https://discourse.julialang.org/t/subtyping-directly-in-parametrics-types/129949/5 "2025-06-17T19:59:58Z")

</div>

> [@Benny](#):
>
> `Vector{Union{Missing, U} where U <: Real}`

So you mean:  
`Vector{Union{Missing,T} where T <: Real} == Vector{Union{Missing,<:Real}}`

and it seems that:  
`Vector{Union{Missing,Real} == Vector{Union{Missing,<:Real}}`

so as you said, the shorthand is not working with second curly braces. It is good to be aware of this specs.

Thank you for the long…

---

<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:** [June 17, 2025, 8:12pm UTC](https://discourse.julialang.org/t/subtyping-directly-in-parametrics-types/129949/6 "2025-06-17T20:12:33Z")

</div>

TLDR:

- `Union{Missing, <:Real}` is shorthand that creates a new `UnionAll` with an anonymous type variable, and it’s equal to `Union{Missing, T} where {T <: Real}`.
- `Union{Missing, T} where {T <: Real}` is simplified by Julia into `Union{Missing, Real}`, because `Union` is covariant, like `Tuple`.

---

<div class="post-metadata">

**Author:** ![eotero](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eotero/32/36642_2.png) [@eotero](https://discourse.julialang.org/u/eotero)\
**Post date:** [June 17, 2025, 8:59pm UTC](https://discourse.julialang.org/t/subtyping-directly-in-parametrics-types/129949/7 "2025-06-17T20:59:03Z")

</div>

But not working for parametric types like Arrays. Must use the “type variable” and not the shorthand \<:Type for covariation.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [June 17, 2025, 9:03pm UTC](https://discourse.julialang.org/t/subtyping-directly-in-parametrics-types/129949/8 "2025-06-17T21:03:12Z")

</div>

> [@eotero](#):
>
> But not working for parametric types like Arrays.

because most of the time, the types are invariant, which gives property:

```julia
julia> Vector{Int} <: Vector{Real}
false

```

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 17, 2025, 9:31pm UTC](https://discourse.julialang.org/t/subtyping-directly-in-parametrics-types/129949/9 "2025-06-17T21:31:32Z")

</div>

> [@eotero](#):
>
> But not working for parametric types like Arrays. Must use the “type variable” and not the shourthand \<:Type for covariation.

That’s not true.

```julia
julia> Vector{<:Real} == Vector{T} where T<:Real
true

```

Again, the key is 1 level of curly braces. The simplification of unions of unions is a completely separate matter, we can remake the shorthand usage example without that complication:

```julia
julia> Vector{Vector{Int}} <: Vector{Vector{<:Real}}
false

julia> Vector{Vector{Int}} <: Vector{Vector{T}} where T<:Real
true

```

which has the same explanation:

```julia
julia> isconcretetype(Vector{Vector{<:Real}})
true

julia> Vector{Vector{<:Real}} == Vector{Vector{U} where U<:Real}
true

julia> (Vector{Vector{U} where U<:Real}) == (Vector{Vector{T}} where T<:Real)
false

```

---

<div class="post-metadata">

**Author:** ![eotero](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eotero/32/36642_2.png) [@eotero](https://discourse.julialang.org/u/eotero)\
**Post date:** [June 17, 2025, 10:01pm UTC](https://discourse.julialang.org/t/subtyping-directly-in-parametrics-types/129949/10 "2025-06-17T22:01:12Z")

</div>

```julia
julia> Vector{Vector{Int}} <: Vector{Vector{<:Real}}
false

julia> Vector{Vector{Int}} <: Vector{Vector{T}} where T<:Real
true

```

I thought that covariation should deliver true , but with the shorthand is giving false, so it is staying invariant, isn’t it?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 17, 2025, 10:02pm UTC](https://discourse.julialang.org/t/subtyping-directly-in-parametrics-types/129949/11 "2025-06-17T22:02:47Z")

</div>

Again, `Vector{Vector{<:Real}}` is not a shorthand for `Vector{Vector{T}} where T<:Real`, the shorthand only works across 1 layer of curly braces. See my preceding comment for the type it is a shorthand for. Covariance and invariance are red herrings here.
