Hi folks,
I’m quite new to Julia (1.9) so please forgive me if this is a silly request or if I have overseen something. However, I’m currently facing serious troubles/incoveniences while implementing some parametric structures/objects. Especially, defining constructors which allow a flexible usage seems very cumbersome to me, where in my view, an easy solution would exist (or maybe I have overseen something which already exists).
Here, a small example of an actual structure which I want to implement with a ‘flexible’ constructor:
const DRK=Float64 # default real kind
const DIK=Int64 # default integer kind
EleType{RK}=Union{RK,AbstractArray{RK}} where {RK<:Real} # element type
MaxType{IK}=Union{IK,Missing} where {IK<:Integer} # integer or missing (=inf)
# (LAT)itude (VAL)ues
struct LatVal{ET<:EleType}
u::ET # sin(th)
t::ET # cos(th)
end
LatVal{ET}(th::ET) where {ET} = LatVal(sin.(th),cos.(th))
LatVal(th) = LatVal(sin.(th),cos.(th))
# FNAL (P)olynomials, (S)ectorial (ITER)ator
struct PSIter{ET<:EleType,IK<:Integer,MT<:MaxType{IK}}
lVal::LatVal{ET}
mMax::MT
mMin::IK
function PSIter{ET,IK,MT}(th::ET,mMax::MT=missing,mMin::IK=zero(IK)) where {ET<:EleType,IK,MT<:MaxType{IK}}
new(LatVal(th),mMax,mMin)
end
end
PSIter{ET,IK}(th::ET,mMax::MT,mMin::IK) where {ET<:EleType,IK,MT<:MaxType{IK}} = PSIter{ET,IK,MT}(th,mMax,mMin)
PSIter{ET,IK}(th::ET,mMax::MT) where {ET<:EleType,IK,MT<:MaxType{IK}} = PSIter{ET,IK,MT}(th,mMax)
PSIter{ET,IK}(th::ET) where {ET<:EleType,IK} = PSIter{ET,IK,Missing}(th)
PSIter{ET}(th::ET,mMax,mMin::IK) where {ET<:EleType,IK} = PSIter{ET,IK}(th,mMax,mMin)
PSIter{ET}(th::ET,mMax::IK) where {ET<:EleType,IK<:Integer} = PSIter{ET,IK}(th,mMax)
PSIter{ET}(th::ET,mMax::Missing) where {ET<:EleType} = PSIter{ET,DIK}(th,mMax)
PSIter{ET}(th::ET) where {ET<:EleType} = PSIter{ET,DIK}(th)
PSIter(th::ET,mMax,mMin) where {ET<:EleType} = PSIter{ET}(th,mMax,mMin)
PSIter(th::ET,mMax::IK) where {ET<:EleType,IK<:Integer} = PSIter{ET}(th,mMax)
PSIter(th::ET,mMax::Missing) where {ET<:EleType} = PSIter{ET}(th,mMax)
PSIter(th::ET) where {ET<:EleType} = PSIter{ET,DIK}(th)
Note all the extra definitions which I need (12!) to allow omitting parameters and optional arguments. This makes the code very confusing and overloaded and I would have to do similar definitions for several other constructors. In my view, if one would allow optional parameters in the constructor, one could save ALL these extra definitions. I have something like this in mind:
# FNAL (P)olynomials, (S)ectorial (ITER)ator
struct PSIter{ET<:EleType,IK<:Integer,MT<:MaxType{IK}}
lVal::LatVal{ET}
mMax::MT
mMin::IK
function PSIter{ET=DRK,IK=DIK,MT=Missing}(th::ET,mMax::MT=missing,mMin::IK=zero(IK)) where {ET<:EleType,IK,MT<:MaxType{IK}}
new(LatVal(th),mMax,mMin)
end
end
With the (in my view correct) behavior:
[1. Use the specified parameter, if provided, try to convert actual arguments accordingly] > [2. Infer actual parameter from provided arguments] > [3. use the default parameter if not inferable]
Another things that bores me is that I’m not allowed to specify optional arguments in the extra definitions outside the inner constructor. Something like this is currently not working (in Julia 1.9):
PSIter{ET,IK}(th::ET,mMax::MT=missing,mMin::IK=zero(DIK)) where {ET<:EleType,IK,MT<:MaxType{IK}} = PSIter{ET,IK,MT}(th,mMax,mMin)
So I have to write 3 definitions in my case (instead of one) to express optional arguments
What do you think about this? Have I missed something which already exists?