# Calculated type parameter warntype

in the following, I’m trying to put some calculated values as type parameters:

``````julia> struct A{Plus, Minus}
A(x, y) = new{x + y, x - y}()
end

julia> A(2, 3)
A{5,-1}()

julia> @code_warntype A(2, 3)
Variables
#self#::Type{A}
x::Int64
y::Int64

Body::A{_A,_B} where _B where _A
1 ─ %1 = (x + y)::Int64
│   %2 = (x - y)::Int64
│   %3 = Core.apply_type(Main.A, %1, %2)::Type{A{_A,_B}} where _B where _A
│   %4 = %new(%3)::A{_A,_B} where _B where _A
└──      return %4
``````

how to avoid the above warntype in construction? thanks.

As stated it’s impossible since the compiler, with the info given, has absolutely no idea what `x` and `y` are and therefore couldn’t possibly infor the type you are constructing.

OTOH, without any change, when `x` and `y` are statically known constant propagation should work.

``````julia> struct A{Plus, Minus}
A(x, y) = new{x + y, x - y}()
end

julia> f() = A(1, 2)
f (generic function with 1 method)

julia> @code_warntype f()
Variables
#self#::Core.Compiler.Const(f, false)

Body::A{3,-1}
1 ─ %1 = Main.A(1, 2)::Core.Compiler.Const(A{3,-1}(), false)
└──      return %1
``````

seems like using `Var` is the only way?

``````julia> struct B{Plus, Minus}
B(::Val{x}, ::Val{y}) where {x, y} = new{x + y, x - y}()
end

julia> B(Val(2), Val(3))
B{5,-1}()

julia> @code_warntype B(Val(2), Val(3))
Variables
#self#::Type{B}
#unused#@_2::Core.Compiler.Const(Val{2}(), false)
#unused#@_3::Core.Compiler.Const(Val{3}(), false)

Body::B{5,-1}
1 ─ %1 = (\$(Expr(:static_parameter, 1)) + \$(Expr(:static_parameter, 2)))::Core.Compiler.Const(5, false)
│   %2 = (\$(Expr(:static_parameter, 1)) - \$(Expr(:static_parameter, 2)))::Core.Compiler.Const(-1, false)
│   %3 = Core.apply_type(Main.B, %1, %2)::Core.Compiler.Const(B{5,-1}, false)
│   %4 = %new(%3)::Core.Compiler.Const(B{5,-1}(), false)
└──      return %4
``````

Sure, if you already have those values in the type parameter you can do whatever you want.

But it’s by all mean not the “only way”. In fact, it’s neither a “way” nor is it the “only” way to achieve the same effect.

It’s not a solution since you are just moving where the type instability is and it won’t help much in real code,

``````julia> @code_warntype Val(2)
Variables
#self#::Type{Val}
x::Int64

Body::Val{_A} where _A
1 ─      nothing
│   %2 = Core.apply_type(Base.Val, x)::Type{Val{_A}} where _A
│   %3 = (%2)()::Val{_A} where _A
└──      return %3
``````

It’s not the only way to achieve this since you can go with whatever type parameter you like,

``````julia> struct C{P, M}
C(::NTuple{x}, ::NTuple{y}) where {x, y} = new{x + y, x - y}()
end

julia> @code_warntype C((1, 2, 3), (2, 3))
Variables
#self#::Type{C}
#unused#@_2::Tuple{Int64,Int64,Int64}
#unused#@_3::Tuple{Int64,Int64}

Body::C{5,1}
1 ─ %1 = (\$(Expr(:static_parameter, 1)) + \$(Expr(:static_parameter, 2)))::Core.Compiler.Const(5, false)
│   %2 = (\$(Expr(:static_parameter, 1)) - \$(Expr(:static_parameter, 2)))::Core.Compiler.Const(1, false)
│   %3 = Core.apply_type(Main.C, %1, %2)::Core.Compiler.Const(C{5,1}, false)
│   %4 = %new(%3)::Core.Compiler.Const(C{5,1}(), false)
└──      return %4
``````
2 Likes

oh my god! the fact that `Val(x)` gives warntype is so shocking as it’s so widely used!!!

Most use of it where the argument isn’t a constant or type parameter is wrong.

(deleted). thanks.