# TraitWrapper - an idea for developing a traits based system

**URL:** <https://discourse.julialang.org/t/traitwrapper-an-idea-for-developing-a-traits-based-system/31179>\
**Category:** General Usage\
**Tags:** proposal, traits\
**Created:** [November 17, 2019, 1:16pm UTC](https://discourse.julialang.org/t/traitwrapper-an-idea-for-developing-a-traits-based-system/31179 "2019-11-17T13:16:28Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [November 17, 2019, 1:16pm UTC](https://discourse.julialang.org/t/traitwrapper-an-idea-for-developing-a-traits-based-system/31179/1 "2019-11-17T13:16:28Z")

</div>

I read with interests [The Emergent Features of JuliaLang: Part II - Traits](https://invenia.github.io/blog/2019/11/06/julialang-features-part-2/) and have been thinking about traits lately. I think I understand how Holy Traits work but I feel unsatisfied with it.

The examples and the blogs I have seen are based on using traits on one of the arguments. But in my use-case, I have multiple arguments that I want to use traits with.

The use-case I have is [JLBoost.jl](https://github.com/xiaodaigh/JLBoost.jl)’s tree boosting algorithm. At some stage, I want to use a `predict` function to score out a bunch of trees on a `DataFrame`.

The current function signature looks like this

```julia
function predict(jlts::AbstractVector{T}, df::AbstractDataFrame) where T <:AbstractJLBoostTree
	mapreduce(x->predict(x, df), +, jlts)
end

```

The two arguments are `jlts` and `df` and as you can see it’s just using the `mapreduce` function. Actually, I don’t require `jlts` to be `AbstractVector{T<:AbstractJLBoostTree}` nor `df` to be `AbstractDataFrame` at all.

I just need `jlts` to be an iterable of `S<:AbstractJLBoostTree` and `df` to be that something supports `df[!, column]` syntax. So naturally, I want to use traits. But if I use Holy traits I would end up with functions like this

```julia
function predict(jlts, df)
    predict(Iterable(jlts), ColumnAccessible(df), jlts, df)
end

function predict(::Iterable{T}, ::ColumnAccessible, jlts, df) where T <:AbstractJLBoostTree
	mapreduce(x->predict(x, df), +, jlts)
end

```

Again, I find that unsatisfying and I was thinking about this concept of a `TraitWrapper` where the `Trait` type contains the object that you want to use. E.g.

```julia
abstract type TraitWrapper{T} end

struct IterableTraitWrapper{T} <: TraitWrapper{T}
   object::T
   IterableTraitWrapper(t::T) where T = begin
      if hasmethod(iterate, Tuple{T})
      	new{T}(t)
      else 
         throw("This is not iterable")
      end
   end
end

struct ColumnAccessibleTraitWrapper{T} <: TraitWrapper{T}
   object::T
   ColumnAccessibleTraitWrapper(t::T) where T = begin
      if hasmethod(getindex, Tuple{DataFrame, typeof(!), Symbol})
      	new{T}(t)
      else 
         throw("This is not ColumnAccessible")
      end
   end
end

object(t::TraitWrapper) = t.object

```

Now I can just use my traits signature like so

```julia
function predict(jlts, df)
    predict(IterableTraitWrapper(jlts), ColumnAccessibleTraitWrapper(df))
end

function predict(jlts::IterableTraitWrapper, df::ColumnAccessible)
	mapreduce(x->predict(x, object(df)), +, object(jlts))
end

```

So that if I need more traits in a function signature I can just do that and not have to double the number of arguments. I also find the `TraitWrapper` to be clearer as I can see which trait corresponds to which argument better and I am clearly expressing which argument I expect to have a certain trait.

I am quite new to the traits systems in Julia, but I find this `TraitWrapper` idea very appealing and I wonder if it’s already done elsewhere. And I wouldn’t be surprised.

Another approach I thought of is to combine the two arguments into one trait, which might work too. Happy to hear ideas from elsewhere in the Julia-ecosystem.

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [November 17, 2019, 4:14pm UTC](https://discourse.julialang.org/t/traitwrapper-an-idea-for-developing-a-traits-based-system/31179/2 "2019-11-17T16:14:19Z")

</div>

I think this makes sense as a thing to do.

Note: your example traits are both dynamic, so do not compile away.  
(At least for now. See also Tricks.jl)

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [November 17, 2019, 5:53pm UTC](https://discourse.julialang.org/t/traitwrapper-an-idea-for-developing-a-traits-based-system/31179/3 "2019-11-17T17:53:09Z")

</div>

Worth trying; seems closer to a `CharacteristicWrapper` which would be helpful in its own right and somewhat orthogonal to the machinery and algorithmic specialization that Holy Traits embody.

@maruo3 do you see a clean and helpful way to package this approach or some variant stemming from this approach?

---

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [November 18, 2019, 12:59pm UTC](https://discourse.julialang.org/t/traitwrapper-an-idea-for-developing-a-traits-based-system/31179/4 "2019-11-18T12:59:32Z")

</div>

Tidied up my thinking and put it in a package [https://github.com/xiaodaigh/TraitWrappers.jl](https://github.com/xiaodaigh/TraitWrappers.jl)

---

<div class="post-metadata">

**Author:** ![sairus7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sairus7/32/10816_2.png) [@sairus7](https://discourse.julialang.org/u/sairus7)\
**Post date:** [November 18, 2019, 3:02pm UTC](https://discourse.julialang.org/t/traitwrapper-an-idea-for-developing-a-traits-based-system/31179/5 "2019-11-18T15:02:50Z")

</div>

And what if you need to dispatch not on a single object trait, but a combination of several traits of a single object?

---

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [November 18, 2019, 11:32pm UTC](https://discourse.julialang.org/t/traitwrapper-an-idea-for-developing-a-traits-based-system/31179/6 "2019-11-18T23:32:12Z")

</div>

That is a very good question. Must admit I haven’t thought too much about that. But I think you would define a new Trait which is the trait that satisfies all those traits. Maybe providing convenience functions to make it easy to to define such a trait would do the trick.

Been reading into Traitor.jl, I think their system is quite nice and maybe TraitWrappers.jl isn’t really necessarily. But it’s an interesting intellectual exercise for me.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 18, 2019, 11:39pm UTC](https://discourse.julialang.org/t/traitwrapper-an-idea-for-developing-a-traits-based-system/31179/7 "2019-11-18T23:39:02Z")

</div>

> [@xiaodai](#):
>
> Been reading into Traitor.jl, I think their system is quite nice and maybe TraitWrappers.jl isn’t really necessarily. But it’s an interesting intellectual exercise for me.

Probably something like TraitWrappers could be useful in reviving / mimicking Traitor.

---

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [November 18, 2019, 11:43pm UTC](https://discourse.julialang.org/t/traitwrapper-an-idea-for-developing-a-traits-based-system/31179/8 "2019-11-18T23:43:16Z")

</div>

[https://github.com/mauro3/SimpleTraits.jl](https://github.com/mauro3/SimpleTraits.jl) is alive. Seems to have adopted some Traitor.jl like syntax.

---

<div class="post-metadata">

**Author:** ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)\
**Post date:** [November 19, 2019, 8:17am UTC](https://discourse.julialang.org/t/traitwrapper-an-idea-for-developing-a-traits-based-system/31179/9 "2019-11-19T08:17:05Z")

</div>

Yes, SimpleTraits.jl is alive, and I’m planning to keep it that way. But I will probably not have time to extend its functionality. I think it can be attractive to use in “normal” cases, like your example above. It helps to reduce boiler-plate, keep the code consistent (there are several ways to implement THT), as well as clearly marking places where you use traits. But it’s not as powerful as hand-coding, so you can’t do more complicated cases. (Although, it handles two-type traits just fine.)

I think your trick is potentially nice, moving boiler plate from trait-functions to trait definitions. Although, youR `IterableTraitWrapper` errors when used with a non-iterator, so maybe in the `else` clause of the constructor, you should return something like `Not(new{T}(t))`?

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [November 25, 2019, 4:57am UTC](https://discourse.julialang.org/t/traitwrapper-an-idea-for-developing-a-traits-based-system/31179/10 "2019-11-25T04:57:47Z")

</div>

There are many more `types` than `traits`, and that is likely to remain so. What if we were to use the machinery of `abstract types` and `singleton structs` in an orthogonal manner, providing `abstract traits` and `singleton traitstates`? There would be distinct pools; `types` and `traits` would be separate in memory.

With that, we could support (at least) single trait augmented abstract single  
inheritance; and, probably – as most distinct traits do not create diamonds – several trait augmented abstract single inheritance. Moreover, one trait may be introduced at an earlier level of type abstraction and another associated at a later unfolding of the line of abstract inheritance.
