# Inheritance or trait function?

**URL:** <https://discourse.julialang.org/t/inheritance-or-trait-function/4873>\
**Category:** General Usage\
**Tags:** question, type, traits\
**Created:** [July 15, 2017, 5:39pm UTC](https://discourse.julialang.org/t/inheritance-or-trait-function/4873 "2017-07-15T17:39:07Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [July 15, 2017, 5:39pm UTC](https://discourse.julialang.org/t/inheritance-or-trait-function/4873/1 "2017-07-15T17:39:07Z")

</div>

I am facing a problem for which I am not 100% sure of the pros and cons of two different solutions. Imagine that I have an abstract type:

```julia
abstract type A end

```

and various concrete types:

```julia
struct T1 <: A end
struct T2 <: A end
# ...

```

Some of these types have a property, let’s say `iscool(::T1) = true` and `iscool(::T2) = false`. I wonder what are the pros and cons of specializing a method `iscool` for each type versus adding a new level of inheritance:

```julia
abstract type A end
abstract type Acool <: A end

struct T1 <: Acool end
struct T2 <: A end

```

At the caller site, I would be using either one of the following to determine the coolness of the object:

- `iscool(obj)`
- `obj isa Acool`

Could you please share your suggestions for choosing one solution over the other or any other better solution that you know in Julia?

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [July 15, 2017, 7:13pm UTC](https://discourse.julialang.org/t/inheritance-or-trait-function/4873/2 "2017-07-15T19:13:27Z")

</div>

What if you want to also add the spicyness of the object? With traits you just define another function. With inheritance you do what?

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [July 15, 2017, 7:23pm UTC](https://discourse.julialang.org/t/inheritance-or-trait-function/4873/3 "2017-07-15T19:23:51Z")

</div>

Very good point, this is definitely something to consider 👍

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [July 15, 2017, 7:31pm UTC](https://discourse.julialang.org/t/inheritance-or-trait-function/4873/4 "2017-07-15T19:31:19Z")

</div>

Can we say that inheritance is the go-to solution only in cases where we can exploit the dispatch system? I understand that the `iscool` method will be checked in a `if-else` statement whereas the `Acool` type could be passed in as an argument to a function for a specialized implementation. So, if the `if-else` statement is called 1000000 times we have a performance issue, whereas the dispatch solution has no bottlenecks.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [July 15, 2017, 7:36pm UTC](https://discourse.julialang.org/t/inheritance-or-trait-function/4873/5 "2017-07-15T19:36:53Z")

</div>

> [@juliohm](#):
>
> I understand that the iscool method will be checked in a if-else statement whereas the Acool type could be passed in as an argument to a function for a specialized implementation. So, if the if-else statement is called 1000000 times we have a performance issue, whereas the dispatch solution has no bottlenecks.

No, I went through this pretty extensively.

> **[Type-Dispatch Design: Post Object-Oriented Programming for Julia - Stochastic...](http://www.stochasticlifestyle.com/type-dispatch-design-post-object-oriented-programming-julia/)**
>
> In this post I am going to try to explain in detail the type-dispatch design which is used in Julian software architectures. It’s modeled after the design of many different packages and Julia Base, and has been discussed in parts elsewhere. This is...

Try it yourself: the `iscool(A::T1)=true` will compile away in each of its usages (when `A` can be inferred as a `T1`, same as static vs dynamic dispatch). So the compiler uses this just fine and there’s no performance penalty for doing it like this. You can do this to build dispatch on traits which would be static dispatch actually.

It’s a style choice, not a performance choice.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [July 15, 2017, 7:38pm UTC](https://discourse.julialang.org/t/inheritance-or-trait-function/4873/6 "2017-07-15T19:38:54Z")

</div>

No, you can use “Holy Traits” to have run time free traits [StridedArray should be an abstract class, not a union · Issue #2345 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/2345#issuecomment-54537633)

This is for example used for defining if abstract arrays support efficient linear indexing or not.

---

<div class="post-metadata">

**Author:** ![bicycle1885](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bicycle1885/32/107_2.png) [@bicycle1885](https://discourse.julialang.org/u/bicycle1885)\
**Post date:** [July 16, 2017, 3:37pm UTC](https://discourse.julialang.org/t/inheritance-or-trait-function/4873/7 "2017-07-16T15:37:03Z")

</div>

Defining type-level methods is my favorite approach.

```julia
iscool(::Type{<:A}) = false # not cool by default
iscool(x::A) = iscool(typeof(x)) # value-level fallback method
iscool(::Type{T1}) = true # but T1 is cool

```

This will also be optimized away and there is no runtime cost as long as it is type-stable. Type-level metaprogramming like generated functions works, too.
