# "Traits" which may be defined on types or values?

**URL:** <https://discourse.julialang.org/t/traits-which-may-be-defined-on-types-or-values/48919>\
**Category:** General Usage\
**Tags:** traits\
**Created:** [October 24, 2020, 1:29am UTC](https://discourse.julialang.org/t/traits-which-may-be-defined-on-types-or-values/48919 "2020-10-24T01:29:31Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![evanfields](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evanfields/32/1744_2.png) [@evanfields](https://discourse.julialang.org/u/evanfields)\
**Post date:** [October 24, 2020, 1:29am UTC](https://discourse.julialang.org/t/traits-which-may-be-defined-on-types-or-values/48919/1 "2020-10-24T01:29:31Z")

</div>

I’m trying to learn about [Holy] traits for the first time. It seems that in the classic implementation, an object’s traitfulness depends only on that object’s type, not value. For example, maybe I want to classify certain types as cool or not:

```julia
abstract type SweetTrait end
struct IsSweet <: SweetTrait end
struct NotSweet <: SweetTrait end

SweetTrait(::Type) = NotSweet() # default is not sweet
SweetTrait(::Type{Rational}) = IsSweet() # rationals are cool
SweetTrait(::Type{String}) = IsSweet()

announce(x::T) where {T} = announce(SweetTrait(T), x)
announce(::IsSweet, x) = println("$x is cool")
announce(::NotSweet, x) = println("$x is boring")

```

But what if I want some objects’ traitfulness to depend on the actual values, not just the object type? The following _seems_ to work, but it’s a pattern I don’t think I’ve seen in the traits examples. Is it non-performant, an antipattern? Is there a better way to accomplish this?

```julia
SweetTrait(::Any) = NotSweet() # default is not sweet
SweetTrait(::Rational) = IsSweet() # rationals are cool
SweetTrait(x::Int) = ifelse(x == 47, IsSweet(), NotSweet()) # 47 is the only cool integer

announce(x)= _announce(SweetTrait(x), x)
_announce(::IsSweet, x) = println("$x is cool")
_announce(::NotSweet, x) = println("$x is boring")

```

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [October 24, 2020, 2:13am UTC](https://discourse.julialang.org/t/traits-which-may-be-defined-on-types-or-values/48919/2 "2020-10-24T02:13:31Z")

</div>

> [@evanfields](#):
>
> Is it non-performant

It is not type stable. You could use enums instead, and dispatch using branches.

---

<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:** [October 24, 2020, 4:46am UTC](https://discourse.julialang.org/t/traits-which-may-be-defined-on-types-or-values/48919/3 "2020-10-24T04:46:23Z")

</div>

You could also use `Val` for this, i.e. something along the lines of

```julia
SweetTrait(x::Int) = SweetTrait(Val(x))
SweetTrait(::Val{N}) = NotSweet()
SweetTrait(::Val{47}) = IsSweet()

```

---

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [October 24, 2020, 8:08am UTC](https://discourse.julialang.org/t/traits-which-may-be-defined-on-types-or-values/48919/4 "2020-10-24T08:08:57Z")

</div>

But also not type-stable (with the exception of constant-propagation). This is a case where a nuanced choice is required. `Val` tricks or traits based on _values_ do have a place in allowing you to create APIs that may be readily extended by others, so there are occasions where I might choose to do things this way. But I’d do it with awareness that performance was going to take an orders-of-magnitude hit, so I’d make this kind of choice only when performance of this part of the code is irrelevant. By co-opting dispatch for this, you’re signing up for _runtime_ dispatch, which is vastly more expensive than the enum & branches approach suggested by @Elrod.

In contrast, traits/Val tricks based on types are “free”, because the types are known to inference so it knows what the trait-type will be and can decide the dispatch at compile time (as long as inference “works” on your code, which it does on most well-designed code).

---

<div class="post-metadata">

**Author:** ![Olivier\_Merchiers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/olivier_merchiers/32/4073_2.png) [@Olivier\_Merchiers](https://discourse.julialang.org/u/Olivier_Merchiers)\
**Post date:** [October 24, 2020, 8:17am UTC](https://discourse.julialang.org/t/traits-which-may-be-defined-on-types-or-values/48919/5 "2020-10-24T08:17:52Z")

</div>

> [@Elrod](#):
>
> You could use enums instead, and dispatch using branches

That sounds interesting. Could you give a small example of how to do that exactly?

---

<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:** [October 24, 2020, 8:53am UTC](https://discourse.julialang.org/t/traits-which-may-be-defined-on-types-or-values/48919/6 "2020-10-24T08:53:39Z")

</div>

Thanks for the explanation! I am not yet always aware of performance issues, but sure, eager to learn. Then, too, be interested in an enum & branch approach.

---

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [October 24, 2020, 9:06am UTC](https://discourse.julialang.org/t/traits-which-may-be-defined-on-types-or-values/48919/7 "2020-10-24T09:06:01Z")

</div>

It’s simpler than you may be imagining. Here’s one that doesn’t involve `Enum` (that’s kind of an independent issue):

```julia
function foo(x)
    x > 47 && return foo_big(x)
    x > 13 && return foo_medium(x)
    return foo_small(x)
end

```

This involves at most 2 comparison operations, and the compiler can compile-time-dispatch each call site (there are 3 methods that might be called, but there are 3 sites from which you make that call, so it all works out). In contrast, one that looks more like runtime dispatch,

```julia
function foo_rt(x)
    t = x > 47 ? Big() : (x > 13 ? Medium() : Small())
    foo_rt(t, x)
end

```

you have just a single call site that might go 3 places. This is not a perfect example, because since there are only 3 choices Julia will use [union-splitting](https://julialang.org/blog/2018/08/union-splitting/), but in a case where there are more possibilities (like `Val(x)`) then Julia can’t use union-splitting.

---

<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:** [October 24, 2020, 10:18am UTC](https://discourse.julialang.org/t/traits-which-may-be-defined-on-types-or-values/48919/8 "2020-10-24T10:18:55Z")

</div>

Thanks for the explanation and perfect illustration.

---

<div class="post-metadata">

**Author:** ![evanfields](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evanfields/32/1744_2.png) [@evanfields](https://discourse.julialang.org/u/evanfields)\
**Post date:** [October 24, 2020, 3:16pm UTC](https://discourse.julialang.org/t/traits-which-may-be-defined-on-types-or-values/48919/9 "2020-10-24T15:16:31Z")

</div>

Thanks for the helpful response! Can you give an example of when `Val` tricks or values-traits _do_ make sense?

I’m imagining something like using values-traits as syntactic sugar to choose an algorithm based on values? E.g. maybe you have heuristic `A` which works on all vectors and `B` which works on vectors with only nonnegative values, but both `A` and `B` have runtime \>\>\> runtime dispatch cost, so it’s okay to use value-traits to choose the algorithm at runtime? Though now that I write that, this case seems like a natural fit for manual `if` dispatch, so maybe you meant value-traits and kin thereof are appropriate for a different use case?

---

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [October 24, 2020, 3:21pm UTC](https://discourse.julialang.org/t/traits-which-may-be-defined-on-types-or-values/48919/10 "2020-10-24T15:21:08Z")

</div>

Maybe a UI that dispatches on keypresses?

```julia
function handle_keypress(guidata, ::Val{'c'})
    # do something when the user presses 'c'
end

function handle_keypress(guidata, ::Val{Key}) where Key
    error("No handler for ", Key, " has been defined")
end

```

This would make it easy for others to add additional functionality just by defining new `handle_keypress` methods in their local codebase.

This is definitely _not_ a situation demanding high performance, and a trick like this should never be used when performance is necessary.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [October 24, 2020, 6:08pm UTC](https://discourse.julialang.org/t/traits-which-may-be-defined-on-types-or-values/48919/11 "2020-10-24T18:08:22Z")

</div>

The other place where val based dispatch makes sense is places where you expect the value to be a constant in the code. Then you generally get constant folding to eliminate the issue.
