Hi everyone,
I have a questions regarding return types in functions. In principle, I have 2 similar structs (one is bigger, one smaller) defined, and for convenience, I want to auto-fill some fields with default values if they are not explicitly stated - I did this via methods. A short version is given here:
using Distributions
abstract type PLAN{A<:VariateForm} end
struct PLAN1{A,B} <: PLAN{A}
a::Vector{Distribution{A}}
b::Vector{B}
PLAN1{A,B}(a,b) where {A,B} = new(a,b)
end
struct PLAN2{A,B} <: PLAN{A}
a::Vector{Distribution{A}}
b::Vector{B}
c::Dict{Symbol, Vector{C} where {C} }
PLAN2{A,B}(a,b,c) where {A,B,C} = new(a,b,c)
end
#####################################
#Methods
PLAN1(a::AbstractVector{<:Distribution{A}}, b::AbstractVector{B}) where {A,B} = PLAN1{A,B}(a,b)
PLAN2(a::AbstractVector{<:Distribution{A}}, b::AbstractVector{B}, c::Dict{Symbol, <:AbstractVector{C} where {C} }) where {A,B} = PLAN2{A,B}(a,b,c)
#PlAN2 without c field gets as default empty set
PLAN2(a::AbstractVector{<:Distribution{A}}, b::AbstractVector{B}) where {A,B} = PLAN2(a, b, Dict(:∅ => []))
#####################################
#Working as expected
plan1 = PLAN1( [Normal(1,2), Gamma(1,2)], [0.9, 0.1] )
plan2 = PLAN2( [Normal(1,2), Gamma(1,2)], [0.9, 0.1],
Dict(:τ =>[Dirichlet( [1, 2]), Dirichlet( [1, 2])],
:μ => [Normal(1,2), Gamma(1,2)] ) )
#PLAN 2 without c field
plan3 = PLAN2( [Normal(1,2), Gamma(1,2)], [0.9, 0.1])
typeof(plan1) #PLAN1
typeof(plan2) #PLAN2
typeof(plan3) #PLAN2 -> as intended
One could think of PLAN1 as frequentist model, and PLAN2 as Bayesian model, with the field c as prior for the parameter. I would like that my functions, that I have usually written for the frequentist struct PLAN1, are also working for PLAN2 but ignore the prior fields. This usually works with 90% of my functions except when I need to return the same type of the input as output of some function, like here:
function fun1(model::PLAN{A}) where A
#some calculations of the fields PLAN.a and PLAN.b
a_new = model.a #simplified
b_new = model.b #simplified
return ( typeof(model)(a_new,b_new) ) ##ERROR MESSAGE HERE
end
fun1(plan1) #WORKING
fun1(plan2 ) #NOT WORKING?!?
fun1(plan3 ) #NOT WORKING?!?
Question1: I get an error message at the end of fun1 that says ‘no method is defined’ for plan2 and plan3, but I honestly do not know why because I used methods above exactly for the case when the field c
is missing. I tried to google it and to find it here, but my search was not successful. I guess this might be a common beginner mistake, and would be happy if someone could give me a tip/solution what I did wrong or how I could properly use methods such that fun1 also works for plan2
without c
field.
Question2: I am interested if it has any performance implications that I did not define the parametric type C
at the beginning of the struct PLAN2
, but within the field row. The type itself has not any interesting meaning.
Thank you for your inputs and best regards!