Hi all, I have begun to migrate my package from 0.5 to 0.6, and I’ve noticed something interesting regarding type instability between the two. Best to show with code:
0.5
abstract ABC
type A <: ABC
a::Float64
end
type B <: ABC
a::Float64
end
type C{T <: ABC}
a::T
end
Here’s the code_warntype for:
@code_warntype C(A(4.5))
Variables:
#self#::Type{C}
a::A
Body:
begin
return $(Expr(:new, C{A}, :(a)))
end::C{A}
Vs 0.6:
abstract type ABC end
struct A <: ABC
a::Float64
end
struct B <: ABC
a::Float64
end
struct C{T <: ABC}
a::T
end
And the code_warntype:
Variables:
#self#::Any
a::A
Body:
begin
return $(Expr(:new, :($(QuoteNode(C{A}))), :(a)))
end::C{A}
I’m not sure how material this might be in the end (it clearly can resolve the type at the very end), but I’ve noticed particular slow downs in my code between 0.5 and 0.6 where in 0.6 the compiler is unable to resolve certain types that it could in 0.5. Is there some other way we should be defining things?
Thanks!
Chris
OK, that makes sense since it was able to resolve the type in the end. I am however still seeing type instability that I don’t quite understand. I don’t see it in 0.5 and I actually don’t see it in 0.6 while still using “type” to define types (as opposed to struct/mutable struct). Here are the types in question:
mutable struct TermStructureFittingParameter{T <: TermStructure} <: Parameter
times::Vector{Float64}
values::Vector{Float64}
ts::T
end
mutable struct HullWhiteDynamics{P<:Parameter} <: ShortRateDynamics{P}
process::OrnsteinUhlenbeckProcess
fitting::P
a::Float64
sigma::Float64
end
mutable struct OneFactorShortRateTree{S <: ShortRateDynamics, P <: StochasticProcess} <: ShortRateTree
tree::TrinomialTree{P}
dynamics::S
tg::TimeGrid
treeLattice::TreeLattice1D{OneFactorShortRateTree{S, P}}
function OneFactorShortRateTree{S, P}(tree::TrinomialTree{P}, dynamics::S, tg::TimeGrid) where {S, P}
oneFactorTree = new{S, P}(tree, dynamics, tg)
oneFactorTree.treeLattice = TreeLattice1D(tg, get_size(tree, 2), oneFactorTree)
return oneFactorTree
end
end
The compiler in 0.6 with these definitions can’t seem to resolve the type of the HullWhiteDynamics in the Tree type (the last one defined). It has no problem in 0.5 or 0.6 using the “type” keyword. See here, this code_warntype usage is calling a method with the tree passed in as an argument:
Variables:
#self#::QuantLib.#get_state_prices!
tree::QuantLib.OneFactorShortRateTree{QuantLib.HullWhiteDynamics,QuantLib.OrnsteinUhlenbeckProcess}
i::Int64
vs:
Variables:
#self#::QuantLib.#get_state_prices!
tree::QuantLib.OneFactorShortRateTree{QuantLib.HullWhiteDynamics{QuantLib.TermStructureFittingParameter{QuantLib.FlatForwardTermStructure{QuantLib.T
ime.TargetCalendar,QuantLib.Time.Actual365,QuantLib.ContinuousCompounding,QuantLib.Time.Annual}}},QuantLib.OrnsteinUhlenbeckProcess}
i::Int64```
As you can see in the latter output, it knows exactly what type of HullWhiteDynamics is passed in. Is there something wrong with the way I am using struct/mutable struct and some of the new syntax?
Thanks!
Chris
Impossible to tell without full code.
Specifically, a method called “tree” gets called in hull_white.jl (line 42), which is where this tree object is created:
numericTree = OneFactorShortRateTree{HullWhiteDynamics, typeof(numericDynamics.process)}(trinomial, numericDynamics, grid)
In 0.5, when I call this method, it’s able to resolve all the types associated with this obj:
get_state_prices!(numericTree, i)```
In 0.6, it can't.
Just thought I’d update - it seems in 0.5 it was able to resolve just passing in HullWhiteDynamics as the type parameter, but not in 0.6. So I had to call typeof to pass in the exact type. Much better now.