Let’s say I have a type A
a user should easily be able to extend by subtypes and write functions f
, g
, … and so on for. These functions are quite a few let’s say 20.
Furthermore a decorator pattern that decorates A
additionally with B
shall be used as illustrated in the following code
using SimpleTraits
abstract type A end
abstract type B end
@traitdef c{A,B}
struct A1 <: A end
struct A2 <: A end
struct A3{T<:A,S<:B} <: A
a::T
b::S
end
struct B1 <: B end
struct B2 <: B end
@traitimpl c{A1,B1}
@traitfn f(a::A3{T,S},x) where {T <: A, S <: B; c{T,S}} = f(a.a,x) # generic lazy fallback on the non decorated case
@traitfn f(a::A3{T,S},x) where {T <: A, S <: B; !c{T,S}} = error("No fallback")
where we then have the implementations
f(a::A1,x) = x/2 # a lazy default fall back to default
f(a::A3{A1,B2},x) = 2*x # an explicit non-lazy second case
f(a::A2,x) = x-1 # even lazier not using any B
f(a::A3{A2,B2},x) = x-1 # needs explicit implementation, since c{A2,B2} is not a trait
and while I like the lazy lines 1 and 3 and I am fine with the second line if one has an explicit second, non default (non-trait c) default – I have one thing that I don’t like:
One has to provide a line like the fourth for evey function like f as soon as the decorator is like B2
for A1
, i.e. not a lazy fallback.
What I would like to have is the following (even a little more generic)
- If some
d::A3{T,S}
type appears forf
s first argument and there is no explicit implementation like 2 or 4, do a lazy fallback, i.e. fallf
withd.a
. - Implement this in a style like
convert
, such that it works for all functions where someA
argument (likef
s first) appears, for me that also sounds likeconvert
- avoid
SimpleTraits
if there is a simpler solution.
One of my ideas is to use something like
convert(::Type{A1},a::A3{A1,B1}) = a.a
instead of the trait, but I don’t seem to get that working. The goal is to allow for something like the lazy fallback by trait just for all functions like f
.
Can something like that be done with conversions?