# Combining SimpleTraits.jl traits on one type

**URL:** <https://discourse.julialang.org/t/combining-simpletraits-jl-traits-on-one-type/73644>\
**Category:** General Usage\
**Tags:** traits\
**Created:** [December 26, 2021, 2:40pm UTC](https://discourse.julialang.org/t/combining-simpletraits-jl-traits-on-one-type/73644 "2021-12-26T14:40:51Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [December 26, 2021, 2:40pm UTC](https://discourse.julialang.org/t/combining-simpletraits-jl-traits-on-one-type/73644/1 "2021-12-26T14:40:51Z")

</div>

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)

```nohighlight
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

```julia
@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)

```

1. what is a good way to write the case !IsNice _and_ !IsCool ?
2. 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.

```julia
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.

1. If I have `A4` the is nice and cool, which one is called first, (a) or (b) and how could I steer that?

---

<div class="post-metadata">

**Author:** ![FMeirinhos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fmeirinhos/32/19527_2.png) [@FMeirinhos](https://discourse.julialang.org/u/FMeirinhos)\
**Post date:** [December 27, 2021, 5:05pm UTC](https://discourse.julialang.org/t/combining-simpletraits-jl-traits-on-one-type/73644/2 "2021-12-27T17:05:15Z")

</div>

From the [README](https://github.com/mauro3/SimpleTraits.jl#details-of-method-dispatch) on `SimpleTraits.jl` it appears dispatching on multiple traits is not yet possible.

However `WhereTraits.jl` [could possibly support it](https://discourse.julialang.org/t/announcing-traits-jl-a-revival-of-julia-traits/35683/5)!

```julia
using WhereTraits

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

is_nice(::Type{<:A1}) = true
is_nice(::Type{<:DecoA}) = false

is_cool(::Type{<:A2}) = true
is_cool(::Type{<:DecoA}) = false

@traits f(a::TA, x) where {TA <: DecoA, is_nice(TA)} = g(a,x,3)
@traits f(a::TA, x) where {TA <: DecoA, is_cool(TA)} = g(a,x,5)
@traits f(a::TA, x) where {TA <: DecoA, !is_cool(TA), !is_nice(TA)} = "without this the multiple dispatch is ill-defined for `A3`"

@show f(A(),0)
@show f(A1(),0)
@show f(A2(),0)
@show f(A3(),0)

```

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [December 27, 2021, 5:42pm UTC](https://discourse.julialang.org/t/combining-simpletraits-jl-traits-on-one-type/73644/3 "2021-12-27T17:42:00Z")

</div>

Thanks for this nice solution,  
actually @mateuszbaran proposed a solution without `WhereTraits`, since that comes with a lot of dependencies and we want to use it in a lightweight interface. His solution is here

[https://github.com/JuliaManifolds/ManifoldsBase.jl/pull/91#issuecomment-1001498928](https://github.com/JuliaManifolds/ManifoldsBase.jl/pull/91#issuecomment-1001498928)

Just out of curiosity: Your approach would (in the current form) still error on both set to true (my A4) so I would have to give precedence for either cool or nice in a fourth function definition, right?

---

<div class="post-metadata">

**Author:** ![FMeirinhos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fmeirinhos/32/19527_2.png) [@FMeirinhos](https://discourse.julialang.org/u/FMeirinhos)\
**Post date:** [December 27, 2021, 6:12pm UTC](https://discourse.julialang.org/t/combining-simpletraits-jl-traits-on-one-type/73644/4 "2021-12-27T18:12:55Z")

</div>

You could just set a function with proper type signature

```julia
@traits f(a::TA, x) where {TA <: DecoA, is_cool(TA), is_nice(TA)} = "dispatch for `A4`"

```

It’s a shame `WhereTraits.jl` is such a heavy weight, I would also think twice before using it as a major dependency in a package. The solution by @mateuszbaran seems like a nice way around the problem!

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [December 27, 2021, 6:20pm UTC](https://discourse.julialang.org/t/combining-simpletraits-jl-traits-on-one-type/73644/5 "2021-12-27T18:20:19Z")

</div>

Oh, I actually exactly had such a line in mind with my question. One disadvantage of that approach (which Mateusz avoids) is that for 3 one would need 8 cases, for 4 traits 16 and so on, it does not scale well; but thanks for your input, I will report, when we managed to have a solution.

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [April 8, 2022, 2:49pm UTC](https://discourse.julialang.org/t/combining-simpletraits-jl-traits-on-one-type/73644/6 "2022-04-08T14:49:37Z")

</div>

Just to finish this thread, we just released our solution to the question asked, in principle using a list of traits (ordered) here [Decorating/Extending a Manifold · ManifoldsBase.jl](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/decorator.html#Traits-with-an-inheritance-hierarchy)
