If the issue is only factorizing code, wouldn’t it be better to do the reverse, having a type for sets and one for set instances, and have another type representing the ~20 trades, that parametrize the sets?
abstract type Trade end
struct Trade_A <: Trade end
struct Trade_B <: Trade end
# ...
struct RateSet{T<:Trade}
fx_rate::Currency
ir_curve::Interest_Rate
end
struct RateSetInstance{T<:Trade}
fx_rate::Float64
ir_curve::Interpolation
end
You can define functions that use fx_rate
regardless of which type the Rate has but they won’t be type stable:
function get_fx_rate(rs::Union{RateSet,RateSetInstance})
return rs.fx_rate # !!! Not type stable !!! return type is Currency or Float64
end
You can also define behavior for all trades or certain trades only using dispatch:
function generic_method_for_RateSet(rs::RateSet)
# something on any RateSet
end
function compute_rate(ri::RateSetInstance{Trade_A})
# something specific for Trade_A
end
If you really want the type of the field to change like you asked while keeping type concreteness, an option is to put the inner types as parameters:
struct GenericRateSet{T_FX, T_IR}
fx_rate::T_FX
ir_curve::T_IR
GenericRateSet{T_FX, T_IR}(fx_rate::T_FX, ir_curve::T_IR)
#you could check here that T_FX and T_IR are what you expect
new{T_FX, T_IR}(fx_rate, ir_curve)
end
end
and possibly use type aliases for dispatch/syntaxic sugar:
const RateSet = GenericRateSet{Currency,Interest_Rate}
const RateSetInstance = GenericRateSet{Float64,Interpolation}
But this second option in not very idiomatic, if two struct have different fields, make two different structs… Or use a generic struct with untyped field if there is no risk of performance issues.