I recently got a little into SimpleTraits - and I like it quite well. But I have a question considering the combination of traits.
Consider the following MWE (just noticed, maybe AbstractA
is not necessary in general)
using SimpleTraits
abstract type AbstractA end
abstract type DecoA <: AbstractA end
# A few concrete types
struct A <: AbstractA end
struct A1 <: DecoA end
struct A2 <: DecoA end
struct A3 <: DecoA end
# just some function
f(::AbstractA, x) = x+2
g(::DecoA, x, y) = x+y
Now I want to do two decorators, for example
@traitdef IsNice{T}
@traitimpl IsNice{T} <- is_nice(T)
is_nice(::Type{<:A1}) = true
is_nice(::Type{<:A2}) = false
is_nice(::Type{<:DecoA}) = false
@traitdef IsCool{T}
@traitimpl IsCool{T} <- is_cool(T)
is_cool(::Type{<:A1}) = false
is_cool(T::Type{<:A2}) = true
is_cool(T::Type{<:DecoA}) = false
@traitfn f(a::TA, x) where {TA <: DecoA; IsNice{TA}} = g(a,x,3) #(a)
@traitfn f(a::TA, x) where {TA <: DecoA; IsCool{TA}} = g(a,x,5) #(b)
- what is a good way to write the case !IsNice and !IsCool ?
- what is a good way to write the case !IsNice or !IsCool ?
More generically, if I have a set of traits is there a way to define the fallback, that none of them is active?
I want it to fallback to just using f
i.e. I want A3 act similar to A.
print("normal:$(f(A(),0))") # prints: normal:2
println("cool $(f(A2(),0))") #prints: cool: 5
println("neither nice nor cool $(f(A3(),0))") # does not work, since there is no !IsCool cases should behave like A (see Q1)
println("nice $(f(A1(),0))") # does not work since it first „checks“ Cool (defined last; see Q2)
This brings up the idea of preceedence - i.e.
- If I have
A4
the is nice and cool, which one is called first, (a) or (b) and how could I steer that?