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 forfs first argument and there is no explicit implementation like 2 or 4, do a lazy fallback, i.e. fallfwithd.a. - Implement this in a style like
convert, such that it works for all functions where someAargument (likefs first) appears, for me that also sounds likeconvert - avoid
SimpleTraitsif 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?