# Type stability, passing type as argument, where keyword

**URL:** <https://discourse.julialang.org/t/type-stability-passing-type-as-argument-where-keyword/78630>\
**Category:** New to Julia\
**Tags:** type-stability\
**Created:** [March 28, 2022, 6:00pm UTC](https://discourse.julialang.org/t/type-stability-passing-type-as-argument-where-keyword/78630 "2022-03-28T18:00:01Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![stepanzh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stepanzh/32/34851_2.png) [@stepanzh](https://discourse.julialang.org/u/stepanzh)\
**Post date:** [March 28, 2022, 6:00pm UTC](https://discourse.julialang.org/t/type-stability-passing-type-as-argument-where-keyword/78630/1 "2022-03-28T18:00:01Z")

</div>

I’m working on a general interface for a package. I were surprised when I checked code stability. Now I’m feeling that I’m missing something very important about parametric methods.

My question is

**Why `foobar_clsr_1` is type stable whereas `foobar_clsr_2` is not?**

```julia
abstract type AbstractFoo end

struct Foo{T} <: AbstractFoo
    x::T
end

function foofunc(::Type{Foo}, x::AbstractVector)
    return 2x
end

function barfunc(f::Foo)
    return 2f.x
end

function foobar_clsr_1(::Type{T}, b::AbstractVector) where {T}
    fooclsr(x::AbstractVector) = b + foofunc(T, x)
    barclsr(x::AbstractVector) = b + barfunc(T(x))

    return fooclsr, barclsr
end

function foobar_clsr_2(T::Type{<:AbstractFoo}, b::AbstractVector)
    fooclsr(x::AbstractVector) = b + foofunc(T, x)
    barclsr(x::AbstractVector) = b + barfunc(T(x))

    return fooclsr, barclsr
end

foo1, bar1 = foobar_clsr_1(Foo, [10, 10])
foo2, bar2 = foobar_clsr_2(Foo, [10, 10])

```

`@code_warntype` gives this (I’m using julia 1.6.2 on macOS)

```nohighlight
% julia -i test.jl
......
julia> x = [2, 2];

julia> @code_warntype foo1(x)
Variables
  #self#::var"#fooclsr#1"{Foo, Vector{Int64}}
  x::Vector{Int64}

Body::Vector{Int64}
1 ─ %1 = Core.getfield(#self#, :b)::Vector{Int64}
│ %2 = Main.foofunc($(Expr(:static_parameter, 1)), x)::Vector{Int64}
│ %3 = (%1 + %2)::Vector{Int64}
└── return %3

julia> @code_warntype foo2(x)
Variables
  #self#::var"#fooclsr#3"{UnionAll, Vector{Int64}}
  x::Vector{Int64}

Body::Vector{Int64}
1 ─ %1 = Core.getfield(#self#, :b)::Vector{Int64}
│ %2 = Core.getfield(#self#, :T)::UnionAll # (!) UnionAll
│ %3 = Main.foofunc(%2, x)::Vector{Int64}
│ %4 = (%1 + %3)::Vector{Int64}
└── return %4

julia> @code_warntype bar1(x)
Variables
  #self#::var"#barclsr#2"{Foo, Vector{Int64}}
  x::Vector{Int64}

Body::Vector{Int64}
1 ─ %1 = Core.getfield(#self#, :b)::Vector{Int64}
│ %2 = ($(Expr(:static_parameter, 1)))(x)::Foo{Vector{Int64}}
│ %3 = Main.barfunc(%2)::Vector{Int64}
│ %4 = (%1 + %3)::Vector{Int64}
└── return %4

julia> @code_warntype bar2(x)
Variables
  #self#::var"#barclsr#4"{UnionAll, Vector{Int64}}
  x::Vector{Int64}

Body::Any
1 ─ %1 = Core.getfield(#self#, :b)::Vector{Int64}
│ %2 = Core.getfield(#self#, :T)::UnionAll # (!) UnionAll
│ %3 = (%2)(x)::Any
│ %4 = Main.barfunc(%3)::Any
│ %5 = (%1 + %4)::Any
└── return %5

```

---

<div class="post-metadata">

**Author:** ![tomerarnon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomerarnon/32/3170_2.png) [@tomerarnon](https://discourse.julialang.org/u/tomerarnon)\
**Post date:** [March 28, 2022, 6:22pm UTC](https://discourse.julialang.org/t/type-stability-passing-type-as-argument-where-keyword/78630/2 "2022-03-28T18:22:04Z")

</div>

[The reason is that julia avoids specializing on `::Type` except in the case where you do `Type{T} where T`](https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing) like in `foobar_clsr_1`

---

<div class="post-metadata">

**Author:** ![stepanzh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stepanzh/32/34851_2.png) [@stepanzh](https://discourse.julialang.org/u/stepanzh)\
**Post date:** [March 28, 2022, 6:43pm UTC](https://discourse.julialang.org/t/type-stability-passing-type-as-argument-where-keyword/78630/3 "2022-03-28T18:43:30Z")

</div>

Thank you for the link. What does “specialize” mean? Is it “hey, compiler, infer types when possible”? So, `Type{T} where T` forces Julia to “specializing”?

---

<div class="post-metadata">

**Author:** ![longemen3000](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/longemen3000/32/7298_2.png) [@longemen3000](https://discourse.julialang.org/u/longemen3000)\
**Post date:** [March 28, 2022, 6:49pm UTC](https://discourse.julialang.org/t/type-stability-passing-type-as-argument-where-keyword/78630/4 "2022-03-28T18:49:55Z")

</div>

yes, exactly that

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [March 28, 2022, 10:16pm UTC](https://discourse.julialang.org/t/type-stability-passing-type-as-argument-where-keyword/78630/5 "2022-03-28T22:16:40Z")

</div>

If the compiler _specialize_ then it compiles a specific version of the method body for each specific combination of input types, i.e., there are multiple compiled method bodies and, at the function call, dynamic dispatch does not select just the method body but the specific specialization of it.

If the compiler does **not** _specialize_, then it compiles a generic version of the method body, and each combination of input types that leads to that method body will call the same compiled code that should work for any combination of types that lead the dynamic dispatch to that method body.

---

<div class="post-metadata">

**Author:** ![torrance](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/torrance/32/38990_2.png) [@torrance](https://discourse.julialang.org/u/torrance)\
**Post date:** [March 29, 2022, 2:54am UTC](https://discourse.julialang.org/t/type-stability-passing-type-as-argument-where-keyword/78630/6 "2022-03-29T02:54:12Z")

</div>

Another way of saying what the others have said above:

Julia compiles a method based on the **types** of the parameters passed in to the function, _not_ based on the **values**.

In `foobar_clsr_2`, `T` is a _value_ which happens to have a type of `Type`. At compile time, the compiler only knows that this is `Type`. And based on that knowledge, it can’t avoid type instability, which means it’s going to compile a really generic, poorly optimized version of this function that can handle any type T.

On the other hand, `foobar_clsr_1` has a type `T` elevated to the type of the first variable thanks to the parameterization, so the compiler knows about `T` at compile time and can specialize on it. For every new type T that you pass this function, Julia will compile a new optimized version of the function specific to that type.
