# Why does Julia not support multiple traits?

**URL:** <https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278>\
**Category:** Internals & Design\
**Tags:** traits\
**Created:** [August 8, 2017, 11:36am UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278 "2017-08-08T11:36:07Z")\
**Posts on this page:** 20\
**Page:** 2

<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:** [August 11, 2017, 7:46pm UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/21 "2017-08-11T19:46:35Z")

</div>

> [@klacru](#):
>
> I want to preserve the other property of the abstract types, which is the possibility of type parameters.

With traits, these are so-called associated types. I’m just now prototyping them, inspired by this thread.

---

<div class="post-metadata">

**Author:** ![klacru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klacru/32/27890_2.png) [@klacru](https://discourse.julialang.org/u/klacru)\
**Post date:** [August 11, 2017, 7:54pm UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/22 "2017-08-11T19:54:42Z")

</div>

Good to hear! What I don’t understand, why you introduce new terminology (traits vs. abstract types, associated types vs. type parameters). I think, that will change the character of the language much more, than the extension of Julian concepts in my thoughts.

---

<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:** [August 11, 2017, 7:58pm UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/23 "2017-08-11T19:58:59Z")

</div>

That is terminology used elsewhere, for instance Rust. The point is that even though those concepts are similar, they are not equal, thus more names…

---

<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:** [August 11, 2017, 11:00pm UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/24 "2017-08-11T23:00:32Z")

</div>

> [@mauro3](#):
>
> With traits, these are so-called associated types. I’m just now prototyping them,

In case someone is interested:

> <https://github.com/mauro3/SimpleTraits.jl/issues/45>
>
> The \`AbstractArray\` \[interface\](https://docs.julialang.org/en/stable/manual/inte…rfaces/#man-interface-array-1) also encompasses the meaning of the type parameters: \`MyArray{T,N}\` has eltype \`T\` and dim \`N\`. A trait \`LikeArray\` ought to contain these two type parameters also, which in this context are associated types (at least Rust uses this term). Maybe this could be written as \`TraitAbstractArray{TT,2}(SomeTypeWhichIsAlsoArrayLike{P1,P2,TT})\`, which would mean that \`SomeTypeWhichIsAlsoArrayLike{P1,P2,T}\` belongs to the trait and that it has associated types \`eltype==TT\` and \`ndims==2\`. \*\*Note\*\* this syntax is different to the current syntax on master, where the type-parameters are occupied by the types fulfilling (or not) the trait.
> 
> Not sure this is SimpleTraits material but I thought I better write it down somewhere before I forget.

---

<div class="post-metadata">

**Author:** ![andyferris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyferris/32/235_2.png) [@andyferris](https://discourse.julialang.org/u/andyferris)\
**Post date:** [August 12, 2017, 5:01am UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/25 "2017-08-12T05:01:22Z")

</div>

@klacru I think you should feel comforted that there are others that want similar things, and agree that Julia should move to support these things.

The feedback on v1.0 is that it is not to introduce lots of new features but rather to complete any known and necessary breaking changes that would otherwise block improving the language, so that we can get some mileage and stability out of a v1.0, v1.1, etc series of releases.

The thing not mentioned is that trait-based dispatch, multiple inheritance, protocols, mixins, etc are new features and not necessarily breaking. Obviously we may choose to make breaking changes to `Base` when/if any of these become available but we wouldn’t have to do that immediately (I think we’d want them to exist for some time before “good design” becomes obvious).

From my work on Traitor, it would seem to me that one “computable” way to think of traits is that each leaf type has an “abstract supertype” for each “trait dimension”. To get the object’s place in each type tree we use a function - the current one being `typeof` (maybe I should say `identity` if we are already acting from the type domain) but we could also consider `eltype`, `isiterable`, etc. We take an abstract type as the intersection of all the sets of types satisfying each trait constraint.

An example with modern `where` syntax might be something like `f(x::T where eltype(T) <: Number)`. For dispatch to work we need to be able to ask if the input type(s) satisfy a signature (easy) and if one signature is more specific than another signature (also easy if you make the assertion that every trait function is completely orthogonal to the others). Given that traits should be computable, I feel that protocols could easily be traits (but there are subtleties relating to 265 which would need to be dealt with).

However, it would nonetheless require a bunch of work to implement this. Given the interaction between type parameters, varargs, covariance, invariance, and specificity being different to subtyping, it’s already very challenging to get dispatch 100% bug free. In fact, it’s taken a whole bunch of work to even get to where we are where abstract types are sensibly defined in terms of sets of possible concrete types. Adding traits and/or multiple inheritance to the type system would be the logical next step in the journey (from my point of view) but some patience will be required. 🙂

Finally, while multiple inheritance may solve some problems, it doesn’t allow post-hoc annotations of existing types with new traits, which is extremely useful.

---

<div class="post-metadata">

**Author:** ![barche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barche/32/79_2.png) [@barche](https://discourse.julialang.org/u/barche)\
**Post date:** [August 12, 2017, 11:22am UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/26 "2017-08-12T11:22:12Z")

</div>

> [@andyferris](#):
>
> The feedback on v1.0 is that it is not to introduce lots of new features but rather to complete any known and necessary breaking changes that would otherwise block improving the language, so that we can get some mileage and stability out of a v1.0, v1.1, etc series of releases.

I seem to remember that @jeff.bezanson mentioned in his JuliaCon talk that they are still a bit on the fence regarding the choice between multiple inheritance and traits.

To me, it would seem that multiple inheritance could be a better fit for Julia, given that it already dispatches on types. If dispatch on traits also becomes possible, you have to wonder when writing a method if you should define the argument as a trait or a type, and when you should use a trait or a type. I think the distinction between an abstract type and a trait is quite vague and could be a major source for confusion.

> [@andyferris](#):
>
> Finally, while multiple inheritance may solve some problems, it doesn’t allow post-hoc annotations of existing types with new traits, which is extremely useful.

What is the concrete use case for this, actually? Thinking abstractly, it would seem unsafe to add traits to a type while leaving the author of the original type unaware of this. What if he modifies the original type in such a way that adhering to the trait becomes impossible?

Finally, another plus for multiple inheritance is that it makes it easier to map types from languages that also support it, such as Python and C++.

---

<div class="post-metadata">

**Author:** ![andyferris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyferris/32/235_2.png) [@andyferris](https://discourse.julialang.org/u/andyferris)\
**Post date:** [August 12, 2017, 2:56pm UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/27 "2017-08-12T14:56:19Z")

</div>

To be clear, I’m not providing an argument _not_ to do multiple inheritance. If the type intersection algorithms turn out to be easy, then this may well be implemented, and I’m sure that could be great.

However, it’s quite common for a package to extend  
new behaviour including on existing types. As just one example, as a package author I’d like a nice way to organise dispatch on e.g. some subset of `AbstractArray`. E.g. StaticArrays methods are valid not only for `StaticArray` but also `RowVector{<:Any,<:StaticArray}` and similarly for `Symmetric` and other types. A trait I could annotate these with and add specialisations of `Base` functions for in a convenient way would make life a lot easier. More importantly, other array wrappers in third party packages I’m not even aware of could opt into `StaticArray` behaviour in appropriate cases.

Tim Holy traits have been used relatively frequently to control dispatch - because the pattern is useful. Generalising this to multiple traits per function/method which don’t have to be known in advance would provide a strictly more flexible and powerful computational model for dispatch (while still being feasible), and yes it still would totally be well-described by the type system (as an extension of `UnionAll`) and like multiple inheritance, be based on intersections of properties.

The stylistic decision to use traits or types may continue to be a dilemma either way (a la Tim Holy traits, since this let’s you do some things even multiple inheritance will not…).

---

<div class="post-metadata">

**Author:** ![tobias.knopp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tobias.knopp/32/7551_2.png) [@tobias.knopp](https://discourse.julialang.org/u/tobias.knopp)\
**Post date:** [August 12, 2017, 4:50pm UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/28 "2017-08-12T16:50:52Z")

</div>

Could you point to the frequent usage of traits in packages?

Again: how would the Number Type hirarchy expressed using HT? I do not get that.

I further do not see how to attatch an interface to a HT? Isn’t this an orthogonal issue to Type hierarchy vs Traits?

---

<div class="post-metadata">

**Author:** ![jkroso](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jkroso/32/220909_2.png) [@jkroso](https://discourse.julialang.org/u/jkroso)\
**Post date:** [August 13, 2017, 1:08am UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/29 "2017-08-13T01:08:47Z")

</div>

> [@barche](#):
>
> I think the distinction between an abstract type and a trait is quite vague and could be a major source for confusion.

Types are an “is a” relationship. Meaning when you say `Tree <: Graph` you’re saying that a `Tree` is like a `Graph` in some ways but not necessarily all ways.

Traits are a “like a” relationship. Meaning when you say `Graph like_a Tree` you’re saying that `Graph`’s are everything that `Tree`’s are but might be more than just that.

Edit: But I’ve just realized that means that adding a trait is equivalent to adding an abstract type to an existing type so I see where the confusion lies now

---

<div class="post-metadata">

**Author:** ![tobias.knopp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tobias.knopp/32/7551_2.png) [@tobias.knopp](https://discourse.julialang.org/u/tobias.knopp)\
**Post date:** [August 13, 2017, 9:34am UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/30 "2017-08-13T09:34:35Z")

</div>

I don’t see the semantic difference between these two. “Is a” also means that the Type can be much more than the subtype implies. If one inherits from several abstract types this becomes even more obvious.

Maybe we should simply allow to inherit from an interface after its creation. In this way we have a single concept instead of two. One may directly inherit at type definition time but may also defer it.

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [August 13, 2017, 9:57am UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/31 "2017-08-13T09:57:29Z")

</div>

Not sure if my insight adds much to this discussion but the way I view traits is along the lines of interfaces. A trait can be used to group objects by which interfaces they are compatible with. That can be useful to make extremely generic functions and explicitly mentioning only the “traits” I assume the inputs have because I will use them somewhere in my function. This is better than limiting myself to one abstract type root node in a type tree or enumerating all root nodes of type trees that my functions can be expected to work with. Also the error message when incorrectly using a function on inappropriate input will be semantically more rich. Moreover, if one trait always implies another, then I have the option of changing that to a supertype-subtype relationship, in fact I suppose this is the right thing to do. Doing that will save me the effort of explicitly defining which traits each concrete type has but it is understood that all traits of the parent are inherited by its children. But then I suppose there are ways to work around each one of the use cases I mentioned above, so this traits vs multiple inheritance argument may all be just a matter of stylistic preferences. That’s just my 2 cents!

---

<div class="post-metadata">

**Author:** ![jkroso](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jkroso/32/220909_2.png) [@jkroso](https://discourse.julialang.org/u/jkroso)\
**Post date:** [August 13, 2017, 10:07am UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/32 "2017-08-13T10:07:20Z")

</div>

“is a” and “like a” were bad terms to use. If anything I should probably of used them the other way around

> [@tobias.knopp](#):
>
> Type can be much more than the subtype implies

Agreed but each of those things would be orthogonal

> [@tobias.knopp](#):
>
> Maybe we should simply allow to inherit from an interface after its creation

What do you mean by interface? Like an abstract type is used today?

---

<div class="post-metadata">

**Author:** ![jkroso](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jkroso/32/220909_2.png) [@jkroso](https://discourse.julialang.org/u/jkroso)\
**Post date:** [August 13, 2017, 10:12am UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/33 "2017-08-13T10:12:29Z")

</div>

I’m starting to think traits are like multiple inheritance where you can also add abstract types to a type after that type has already been defined.

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [August 13, 2017, 10:20am UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/34 "2017-08-13T10:20:56Z")

</div>

Maybe, I suppose a trait can also be viewed as a mini/soft abstract type that is more of an analogy between types than a philosophical isa relationship. And like all analogies, if an analogy turns out to be deeply rooted in the definitions of the analogical entities, you might and probably should start viewing them as mere realizations of the same abstract concept/type 🙂

---

<div class="post-metadata">

**Author:** ![barche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barche/32/79_2.png) [@barche](https://discourse.julialang.org/u/barche)\
**Post date:** [August 13, 2017, 1:31pm UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/35 "2017-08-13T13:31:50Z")

</div>

Currently, the [manual chapter on interfaces](https://docs.julialang.org/en/stable/manual/interfaces/) describes them as “informal”. Examples of these informal interfaces are Iterable and Indexable, but neither of these have an abstract type associated to them. AbstractArray on the other hand does have an abstract type associated with it. I’m not sure what the reason for this is, but it does seem to indicate that an abstract type can be used to indicate expectations about a certain interface being available. Maybe Iterable and Indexable don’t exist as types because they would conflict with the rest of the type hierarchy, e.g. a String is Indexable but also an AbstractString. With multiple inheritance it would be possible to define abstract types for each interface (if deemed desirable, it may be overkill in many cases).

Traits on the other hand appear to be used mainly to hint at which implementation to choose, such as the indexing type for arrays. I think using them to define families of types that adhere to an interface is abusing them somewhat, and could cause confusion between when to use a trait and when to use an abstract type. So maybe for traits it is enough to stick with the existing mechanism?

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [August 13, 2017, 3:08pm UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/36 "2017-08-13T15:08:14Z")

</div>

> [@barche](#):
>
> I think using them to define families of types that adhere to an interface is abusing them somewhat, and could cause confusion between when to use a trait and when to use an abstract type.

Maybe, but I think at the time being formalizing interfaces is a piece in the puzzle that can only be filled with traits (or maybe multiple inheritance in the future). In fact one can argue that traits do an almost perfect job (to the best I can see) generalizing abstract types and interfaces. Looking back on some of the code I have written, I often started with an extremely generic abstract type, then branched off of it to some slightly less abstract types until I reached all the concrete types at the bottom. But I could have also started with the concrete types and defined certain traits and trait inference rules up what used to be an abstract type tree. But in addition to that, I can also define a trait for all types that are summable, indexable, iterable, differentiable, isbits or even some very local traits as package1-compatible, package2-compatible, etc. I suppose defining each and every one of these as supertypes even in a language supporting multiple inheritance is a bit of an overkill, but something about the word “trait” tells me I can do that!

I guess my slight bias towards traits comes partly from the simple philosophical fact that a parent should not come to existence after its children, but then traits can develop with time. This means that if I notice a trait that different types from different packages have, I can define such a trait in my package and exploit this trait/analogy somehow to provide support for similar types across different packages. Defining a parent in this scenario would contradict this basic philosophical fact.

Disclaimer: I don’t claim deep knowledge of many programming languages, I am merely conveying my perspective.

---

<div class="post-metadata">

**Author:** ![tobias.knopp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tobias.knopp/32/7551_2.png) [@tobias.knopp](https://discourse.julialang.org/u/tobias.knopp)\
**Post date:** [August 13, 2017, 3:43pm UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/37 "2017-08-13T15:43:25Z")

</div>

The situation with AbstractArray and Iterable just shows the limitation of the current system since we do not have multiple inheritance.

The reason traits are used seems to be mainly that they provide a workaround for multiple inheritance. But the concepts are so similar that we really should unify them and come up with a single type system. If extending an existing type is desired then just lets allow it. If it’s called trait or not does not matter IMHO.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [August 14, 2017, 3:27am UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/38 "2017-08-14T03:27:17Z")

</div>

Multiple inheritance versus traits which can be added after-the-fact strike me as having a large similarity to the expression problem but in the type domain. One of the most powerful things about multiple dispatch is not the multiple part, but the _external_ part: i.e. that another person can come along and independently add generic functions that operate on existing types _and_ add new types to which existing generic functions apply. That’s extremely powerful and is a huge part of why generic programming “just works” in Julia. While it seems very powerful – perhaps overly powerful – to be able to add supertypes after-the-fact, it does seem necessary for solving the type-level expression problem. It is possible, however, that we can add multiple inheritance for one case and address the other case via a more flexible but somewhat less convenient mechanism like Holy traits.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [August 14, 2017, 3:32am UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/39 "2017-08-14T03:32:17Z")

</div>

I like the “can do” attitude, but someone does have to implement it 🧐.

---

<div class="post-metadata">

**Author:** ![tobias.knopp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tobias.knopp/32/7551_2.png) [@tobias.knopp](https://discourse.julialang.org/u/tobias.knopp)\
**Post date:** [August 14, 2017, 8:58am UTC](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278/40 "2017-08-14T08:58:45Z")

</div>

That’s not what I wanted to imply. The usual answer one gets here when asking for multiple inheritance is: we don’t need that we have holy traits. And from that point traits and abstract types are thought of as independent things. My opinion is that this is not satisfying. And my proposal is to

1. introduce MI
2. allow to add an abstract type to an existing type after it has been created
3. Introduce interfaces that link methods to an abstract type

Point 2. should hopefully address the concerns of people who prefer traits. Before thinking about actual implementation it would be interesting if the above is actually technical feasible. @jeff.bezanson may answer this.

If the above sounds interesting I could come up with a julep for that.

[Previous page](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278.md?page=1)

[Next page](https://discourse.julialang.org/t/why-does-julia-not-support-multiple-traits/5278.md?page=3)
