# Can the overhead of \`myT{\<:T}\` compared to \`myT{T}\`, where \`T\` is a concrete type, be avoided?

**URL:** <https://discourse.julialang.org/t/can-the-overhead-of-myt-t-compared-to-myt-t-where-t-is-a-concrete-type-be-avoided/122721>\
**Category:** Performance\
**Tags:** parametric-types, union\
**Created:** [November 16, 2024, 9:58pm UTC](https://discourse.julialang.org/t/can-the-overhead-of-myt-t-compared-to-myt-t-where-t-is-a-concrete-type-be-avoided/122721 "2024-11-16T21:58:07Z")\
**Posts on this page:** 4\
**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:** [November 16, 2024, 9:58pm UTC](https://discourse.julialang.org/t/can-the-overhead-of-myt-t-compared-to-myt-t-where-t-is-a-concrete-type-be-avoided/122721/1 "2024-11-16T21:58:08Z")

</div>

I understand that `Vector{<:Float64}` is not the same as `Vector{Float64}` as it allows the bottom type [`Union{}`](https://docs.julialang.org/en/v1/base/base/#Union%7B%7D) to be its element type and is (therefore) not a concrete type:

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

julia> isconcretetype(Vector{<:Float64})
false

```

However, in practice, the user cannot construct an instance of `Union{}`.

Thus, I would imagine that any `UnionAll` of a composite type `MyT{T}`, `MyT{<:T}`, such that `T` is a concrete type, should add no overhead compared to `MyT{T}`. For example, `Vector{<:Float64}` should be as efficient as `Vector{Float64}`.

Unfortunately, this is not the case as of Julia 1.11.1:

```julia
julia> v1 = Vector{Float64}[rand(100) for _ in 1:10];

julia> v2 = Vector{<:Float64}[rand(100) for _ in 1:10];

julia> @benchmark mapreduce(sum, +, $v1)
BenchmarkTools.Trial: 10000 samples with 987 evaluations.
 Range (min … max): 51.570 ns … 102.128 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 52.280 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 53.195 ns ± 3.458 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

   ██ ▁▁ ▁
  ███▇▇▇▇▇█████▇▇▇▇▆▇▆▆▇▇▇▆▆▆▇▄▆▅▅▆▆▅▆▅▄▄▄▄▄▅▆▆▅▆▅▆▅▅▅▅▅▆▅▅▆▅▇ █
  51.6 ns Histogram: log(frequency) by time 70.9 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> @benchmark mapreduce(sum, +, $v2)
BenchmarkTools.Trial: 10000 samples with 858 evaluations.
 Range (min … max): 138.811 ns … 620.629 ns ┊ GC (min … max): 0.00% … 57.99%
 Time (median): 140.909 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 154.184 ns ± 38.408 ns ┊ GC (mean ± σ): 2.36% ± 7.44%

  █▅▄▃▂▂▁▁ ▁ ▂▂ ▁
  ███████████████▇█▇▇▇▇▇▇▇██▇▆▆▅████▇▃▅▃▁▁▃▁▄▁▁▄▁▁▃▁▁▁▁▄▆▆▆▇▆▅▅ █
  139 ns Histogram: log(frequency) by time 340 ns <

 Memory estimate: 160 bytes, allocs estimate: 10.

```

Can this performance degradation be fixed as the compiler gets more optimized/“smarter,” or are there some fundamental reasons that prevent it from happening? Thanks!

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [November 16, 2024, 10:56pm UTC](https://discourse.julialang.org/t/can-the-overhead-of-myt-t-compared-to-myt-t-where-t-is-a-concrete-type-be-avoided/122721/2 "2024-11-16T22:56:32Z")

</div>

> [@frankwswang](#):
>
> the user cannot construct an instance of `Union{}`

That’s true, but you can construct a `Vector{Union{}}`:

```julia
julia> v = Union{}[]
Union{}[]

julia> typeof(v)
Vector{Union{}} (alias for Array{Union{}, 1})

julia> v isa Vector{<:Float64}
true

julia> Vector{<:Float64}[v, [1.0, 2.0]]
2-element Vector{Vector{<:Float64}}:
 Union{}[]
 [1.0, 2.0]

```

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [November 16, 2024, 11:20pm UTC](https://discourse.julialang.org/t/can-the-overhead-of-myt-t-compared-to-myt-t-where-t-is-a-concrete-type-be-avoided/122721/3 "2024-11-16T23:20:14Z")

</div>

I’m curious, do you have a realistic setting where you would manipulate a `Vector{<:Float64}` that is not a `Vector{Float64}`. It seems to me that this overhead will never be faced in practice (@matthias314’s example is rather contrived).

---

<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:** [November 17, 2024, 11:05am UTC](https://discourse.julialang.org/t/can-the-overhead-of-myt-t-compared-to-myt-t-where-t-is-a-concrete-type-be-avoided/122721/4 "2024-11-17T11:05:17Z")

</div>

> [@matthias314](#):
>
> you can construct a `Vector{Union{}}`

Worse, they can have a non-zero length e.g. `Vector{Union{}}(undef, 3)` despite not containing any instances. `isempty` also returns `false`.

`T where T<:Float64` and `Union{Union{}, Float64}` do simplify to `Float64`, so `Vector{T where T<:Float64}` simplifies to `Vector{Float64}` even though `Vector{T} where T<:Float64` does not.
