# Feasibility of adding multiple inheritance to Julia

**URL:** https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382
**Category:** Internals & Design
**Tags:** interface
**Created:** [October 25, 2023, 3:07pm UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382 "2023-10-25T15:07:39Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)
#### Post date: [October 25, 2023, 3:07pm UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/1 "2023-10-25T15:07:39Z")

</div>

The topic of interfaces came up again in [one of the correctness threads](https://discourse.julialang.org/t/did-julia-community-do-something-to-improve-its-correctness/102515). My minimally informed opinion is that the best solution would be to [add multiple inheritance](https://github.com/JuliaLang/julia/issues/5) to the language.

How feasible would it be to add multiple inheritance to Julia? I’m sure it would be quite a bit of work, but my question is not about the amount of work required. What I am wondering is how feasible it is to add multiple inheritance from a language design perspective.

---

<div class="post-metadata">

### Author: ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)
#### Post date: [October 25, 2023, 3:19pm UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/2 "2023-10-25T15:19:28Z")

</div>

Not an answer but relevant reading: [https://github.com/JuliaLang/julia/issues/5](https://github.com/JuliaLang/julia/issues/5)

---

<div class="post-metadata">

### Author: ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)
#### Post date: [October 25, 2023, 3:49pm UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/3 "2023-10-25T15:49:04Z")

</div>

Yep, that’s linked in the original post.

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [October 25, 2023, 4:12pm UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/4 "2023-10-25T16:12:42Z")

</div>

that’s the smallest number of issue (#5) that are still open, by a lot. The next one is [implement zeros() by calling calloc · Issue #130 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/130)

---

<div class="post-metadata">

### Author: ![ToucheSir](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/touchesir/32/14411_2.png) [@ToucheSir](https://discourse.julialang.org/u/ToucheSir)
#### Post date: [October 25, 2023, 4:15pm UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/5 "2023-10-25T16:15:18Z")

</div>

There was a Slack thread about this not too long ago, start [here](https://julialang.slack.com/archives/C67910KEH/p1692720114174239?thread_ts=1692718859.167549&cid=C67910KEH) if interested. TL;DR it is possible to have multiple inheritance + multiple dispatch in the same language (as demonstrated by non-Julia languages), but subtyping in Julia is complicated enough that it’s not clear if/how they’d work together here.

---

<div class="post-metadata">

### Author: ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)
#### Post date: [October 25, 2023, 4:44pm UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/6 "2023-10-25T16:44:51Z")

</div>

Darn. Maybe I’ll have to finally sign up for Slack… 😂

---

<div class="post-metadata">

### Author: ![ParadaCarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paradacarleton/32/20005_2.png) [@ParadaCarleton](https://discourse.julialang.org/u/ParadaCarleton)
#### Post date: [October 25, 2023, 5:10pm UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/7 "2023-10-25T17:10:58Z")

</div>

> [@CameronBieganek](#):
>
> What I am wondering is how feasible it is to add multiple inheritance from a language design perspective.

It’s feasible, [and has already been done in packages](https://github.com/Suzhou-Tongyuan/ObjectOriented.jl). If we just wanted multiple inheritance as fast as possible, we could have it tomorrow. That being said, rushing to have it out tomorrow is probably a bad idea–there are lots of kinks to work out.

AFAICT, it just hasn’t been a priority. It’d be great to have the devs say “Our plan is to get multiple inheritance and traits into the language by 1.X.”

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [October 25, 2023, 6:44pm UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/8 "2023-10-25T18:44:36Z")

</div>

I want to point out that both the linked slack thread as well as issue #5 are about _abstract_ multiple inheritance; not OOP style _concrete_ (multiple) inheritance (i.e., where you inherit fields from your parent), as OOP packages typically implement. I don’t think anyone thinking about traits is considering making concrete types subtypable.

---

<div class="post-metadata">

### Author: ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)
#### Post date: [October 25, 2023, 9:15pm UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/9 "2023-10-25T21:15:14Z")

</div>

Yeah, I’m interested in abstract multiple inheritance, not concrete multiple inheritance. From a cursory look at ObjectOriented.jl, it looks like it implements concrete multiple inheritance.

---

<div class="post-metadata">

### Author: ![ParadaCarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paradacarleton/32/20005_2.png) [@ParadaCarleton](https://discourse.julialang.org/u/ParadaCarleton)
#### Post date: [October 26, 2023, 12:40am UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/10 "2023-10-26T00:40:21Z")

</div>

> [@Sukera](#):
>
> not OOP style _concrete_ (multiple) inheritance (i.e., where you inherit fields from your parent), as OOP packages typically implement.

IIRC, ObjectOriented.jl implements both (with C3 MRO for method inheritance). I’m not 100% sure on the details, though (like how multiple inheritance interacts with multiple dispatch); @thautwarm will know more than me.

---

<div class="post-metadata">

### Author: ![thautwarm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thautwarm/32/37760_2.png) [@thautwarm](https://discourse.julialang.org/u/thautwarm)
#### Post date: [October 26, 2023, 3:04am UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/11 "2023-10-26T03:04:30Z")

</div>

ObjectOriented.jl implements inheritance with composition. Syntax sugars are just provided to do the tedious work.

Abstract multiple inheritance is actually implemented in ObjectOriented.jl as an internal utility, these are the underlying stuffs:

```julia
@oodef struct MyClass3 <: {MyClass1, MyClass2} end

# expands to 

struct var"MyClass1::trait" end # utility type

struct MyClass3 <: Object{
        Union{var"MyClass1::trait", var"MyClass2::trait", var"MyClass3::trait"}}
     _base1::MyClass1
     _base2::MyClass2
end

# ... generated code for defining conventional OOP ops

```

Although we cannot directly define a julia type `MyClass3` that subtypes `MyClass1` and `MyClass2`, the information to construct the required type system is well encoded with:

```julia
Object{Union{
     traitof(Self), traitof(MyParent1), traitof(MyParent2), ...}}

```

This emulation can also do things that abstract multiple inheritance could do.

```julia
using ObjectOriented: @like, @oodef
@oodef struct MyClass1 end
@oodef struct MyClass2 end
@oodef struct MyClass3 <: {MyClass1, MyClass2} end
@oodef struct MyClass4 <: {MyClass1, MyClass2} end

test(x::@like(MyClass1)) = "method for class 1"
test(x::@like(MyClass4)) = "method for class 4"

test(MyClass3()) # => 1
test(MyClass4()) # => 4

```

Of course, this encoding of abstract multiple inheritance is not “native” to Julia. It needs compiler changes to be seamless integrated into Julia (e.g., no need for @like macro).

---

<div class="post-metadata">

### Author: ![thautwarm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thautwarm/32/37760_2.png) [@thautwarm](https://discourse.julialang.org/u/thautwarm)
#### Post date: [October 26, 2023, 3:07am UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/12 "2023-10-26T03:07:23Z")

</div>

Besides, OOP is a just special trait called “Virtual Table Trait”.

If we do need some changes to Julia, I’d vote for enhancement to native trait notation in Julia instead of spending time on OOP stuffs.

---

<div class="post-metadata">

### Author: ![ParadaCarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paradacarleton/32/20005_2.png) [@ParadaCarleton](https://discourse.julialang.org/u/ParadaCarleton)
#### Post date: [October 27, 2023, 2:22am UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/13 "2023-10-27T02:22:57Z")

</div>

Thank you so much for your explanation, this is amazing! 😄

> [@thautwarm](#):
>
> If we do need some changes to Julia, I’d vote for enhancement to native trait notation in Julia instead of spending time on OOP stuffs.

Oh, definitely. I’m not a big fan of OOP myself.

I think people have been talking about multiple inheritance more often than traits recently because it kills both birds with one stone–traits just happen to be a special case of multiple inheritance (just create a trait as a new “abstract type” and then let other types inherit from it).

I think the converse holds as well (you can simulate multiple inheritance with traits), but it’s a much bigger pain.

---

<div class="post-metadata">

### Author: ![ParadaCarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paradacarleton/32/20005_2.png) [@ParadaCarleton](https://discourse.julialang.org/u/ParadaCarleton)
#### Post date: [October 27, 2023, 2:29am UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/14 "2023-10-27T02:29:14Z")

</div>

> [@Sukera](#):
>
> I don’t think anyone thinking about traits is considering making concrete types subtypable.

Funnily enough, though, @Lilith and I were discussing the same approach as ObjectOriented.jl for concrete inheritance with no performance penalty 😅. Concrete types get their own supertype automatically (every `struct X` declaration creates a hidden parent type, `abstract type AbstractX`), and then whenever someone tries to subtype `X`, we just subtype the parent instead. (Thanks for the wonderful ideas, Taine 😄 )

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [October 27, 2023, 8:04am UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/15 "2023-10-27T08:04:09Z")

</div>

The other language I use is Python (also what the aforementioned ObjectOriented.jl is based on), and it made me very pessimistic about multiple inheritance in Julia. Not because it’s impossible, but because automatic single-dispatch method resolution order (MRO) is mostly meaningless and it would make method ambiguities in multiple dispatch even more cryptic. Alternatively, I never want to manually write out the order or be blindsided by an error because an order can’t exist (first example in issue 5).

Python classes can have multiple parent classes, let’s annotate it in a Julia-style as `C <: A, B`. In the case where C lacks a method but both A and B have it, do we prioritize A or B? This becomes somewhat meaningless because C isn’t necessarily (and often isn’t) more A or more B, but we _must_ choose. Python’s MRO is based on the order the superclasses are written, so the MRO here is `C, A, B, object` (`object` is roughly `Any`). In the more complicated case where `A <: A1` and `B <: B1`, the MRO becomes `C, A, A1, B, B1, object`, arriving at mostly meaningless because while I wrote A before B, I certainly did not write A1 before B or B1. I may justify a `CatDog <: Cat, Dog` as more Cat than Dog, but not more Feliformia than Dog. Right after “prefer composition over inheritance”, people say “avoid multiple inheritance” for good reason.

In the simpler case before I gave A and B supertypes, the order is not different from a chain of supertypes `C <: A <: B` being used in Julia’s method dispatch with respect to an argument, so it risks the same method ambiguities as that case. But once we involve multiple depths of supertypes, we contend with automatic and meaningless MROs, and it’ll be so much harder to resolve method ambiguities without resorting to fully concretely typed arguments. Holy traits are great because there is a method for each context, and each context can have single supertyping. So I don’t have to say `CatDog` is more Cat or more Dog, I can check `FeliformiaSpecies(::CatDog)` and find it is a `Cat`.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [October 27, 2023, 9:14am UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/16 "2023-10-27T09:14:30Z")

</div>

> [@Benny](#):
>
> Holy traits are great because there is a method for each context, and each context can have single supertyping.

With Holy Traits, you’re doing that same method ordering by choosing the order you check your traits in with the `if`/`else` clauses of that method; the issue there is that you can’t add a new supertype to your type without adjusting all places where you’ve previously added such an `if`/`else` discriminator.

In my view, this sort of ambiguity is unavoidable, but perfectly predictable. At the time you’re declaring that your type `C` subtypes `A` and `B`, `A` and `B` should already exist, so you should also already know about any potential ambiguities in dispatch that can come up when you use `C`; hence, those ambiguities can & need to be handled for `C` explicitly already. I also think that if both `A` and `B` have an egregious ambiguity in the first place, how can it make sense to define a `C` that ought to behave like both `A` and `B` in the first place? Clearly, that must lead to faulty behavior in those overlapping meanings, no?

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [October 27, 2023, 10:35am UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/17 "2023-10-27T10:35:31Z")

</div>

> [@Sukera](#):
>
> With Holy Traits, you’re doing that same method ordering by choosing the order you check your traits in with the `if` /`else` clauses of that method; the issue there is that you can’t add a new supertype to your type without adjusting all places where you’ve previously added such an `if` /`else` discriminator.

I avoid handling multiple contexts in a method for these reasons.

> [@Sukera](#):
>
> I also think that if both `A` and `B` have an egregious ambiguity in the first place, how can it make sense to define a `C` that ought to behave like both `A` and `B` in the first place?

Right, that’s why multiple inheritance is discouraged. The only way to fix the ambiguity is to order them `C <: A, B`, but that order often doesn’t make sense. There may not even be 1 canonical order we should put in the definition; different trait-checking branches could have different orders.

So, Holy traits don’t replace multiple inheritance to me, it still plays by single-subtyping rules, just in several different contexts and derived from the primary single-supertyping hierarchy. It does provide some of the polymorphism expected from multiple inheritance, though that can also be said of composition, which is suggested over any kind of inheritance. Taking my earlier example, CatDog could just be a composite of Cat and Dog, and I dispatch on the fields.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [October 27, 2023, 11:12am UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/18 "2023-10-27T11:12:02Z")

</div>

> [@Benny](#):
>
> Right, that’s why multiple inheritance is discouraged. The only way to fix the ambiguity is to order them `C <: A, B`, but that order often doesn’t make sense. There may not even be 1 canonical order we should put in the definition; different trait-checking branches could have different orders.

Not necessarily; you can also define a function taking `C` explicitly, where you can then define whichever order you prefer for your `C`. Having multiple abstract inheritance in the language just points that issue out to you immediately, while also allowing you to resolve it cleanly for your context, without having to touch existing functions thanks to multiple dispatch.

> [@Benny](#):
>
> Taking my earlier example, CatDog could just be a composite of Cat and Dog, and I dispatch on the fields.

You can’t always do that composition though, if you don’t have actual `Cat` and `Dog` objects to use for that composition; e.g. if the two are just abstract types!

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [October 27, 2023, 12:06pm UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/19 "2023-10-27T12:06:37Z")

</div>

> [@Sukera](#):
>
> Not necessarily; you can also define a function taking `C` explicitly, where you can then define whichever order you prefer for your `C`. Having multiple abstract inheritance in the language just points that issue out to you immediately, while also allowing you to resolve it cleanly for your context, without having to touch existing functions thanks to multiple dispatch.

We _could_, but that manual case-by-case effort seems to defeat the purpose of supertyping and inheritance to me. If the order isn’t tied to the subtype, the simplest way I can imagine what you described is putting the order right in the argument, like `foo(c::(C <: A, B))`; the set of supertypes must be tied to the type, or else you could arbitrarily attach supertypes. I can see how that would help if it calls `bar(c)` to dispatch to the methods `bar(::A)` or `bar(::B)`. But there’s a couple issues:

1. I _don’t_ want to be stuck annotating an argument concretely; if I make another subtype `C2`, I don’t want to copy methods or resort to metaprogramming. I would instead have methods `foo(::A)` and `foo(::B)` and the dispatch system should figure out `foo(C())` and `foo(C2())`. The only way to do that is put the order in the type definitions.
2. The method ambiguity complexity skyrockets with case-by-case order. Even without involving another subtype, `foo2(c1::(C <: A, B), c2::(C <: B, A)) = bar(c1) + bar(c2)` is incredibly unintuitive. At that point, it’s a lot more sensible to use separate functions.

> [@Sukera](#):
>
> You can’t always do that composition though, if you don’t have actual `Cat` and `Dog` objects to use for that composition; e.g. if the two are just abstract types!

I don’t encounter situations where I need to emulate composition for abstract types that can’t be instantiated; it’s worth refactoring concrete components if it calls for it, especially an example like CatDog. If there aren’t discrete components, then it’s more a case for traits as needed. Multiple inheritance isn’t very useful in OO languages, and newer languages with prominent interfaces are eschewing inheritance altogether.

---

<div class="post-metadata">

### Author: ![ToucheSir](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/touchesir/32/14411_2.png) [@ToucheSir](https://discourse.julialang.org/u/ToucheSir)
#### Post date: [October 27, 2023, 2:12pm UTC](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382/20 "2023-10-27T14:12:08Z")

</div>

I think the problem with saying “I don’t like this, but I like traits” is that traits as currently conceptualized have many of the same issues with complexity and ambiguity around dispatch. In that sense, abstract multiple inheritance _is_ one idea for a trait system. If it helps, think of it as multiple interface conformance instead—this is _not_ the usual concrete or abstract base class multiple inheritance you see in modern OO languages, and I think mixing the two concepts will only lead to confusion.

[Next page](https://discourse.julialang.org/t/feasibility-of-adding-multiple-inheritance-to-julia/105382.md?page=2)
