There are many cases where we would like to assign multiple parents to a given type, e.g:
abstract type Person end
abstract type Soldier <: Person end
abstract type Civilian <: Person end
abstract type Man <: Person end
abstract type Woman <: Person end
struct PrivateClubMember <: Woman, Soldier end
The idea is to be able to write functions for Woman and Soldier that any PrivateClubMember could default to, e.g.
info(pcm::Woman) = ...
rank(pcm::Soldier) = ...
and have an error if we call a function shared by Parent types, e.g:
info(pcm::Soldier) = ...
pcm = PrivateClubMember()
info(pcm)
ERROR: functions shared by parent types must be explicitly defined
for sub-types.
and fix this situation with
info(pcm::PrivateClubMember) = ...
My understanding is that as of today Julia does not support multiple parent types, I wonder:
Is this something Julia will support for Julia 2.0, 3.0… ever?
Is there currently a standard Julia way to handle these scenarios?
In a lot of cases where you need inheritance but there’s not a neat type hierarchy, traits can be a good solution. There’s a nice intro by @oxinaboxhere.
There are also a few packages oriented toward helping with this approach:
These are at varying degrees of stability, so I’d ask around before committing to any one package.
EDIT: This was the first thing that came to mind, but @tbeason 's suggestion of reorganization is probably better if you can make it work with your situation.
In a lot of cases I’d guess you can just reorg what you’ve written to make it work.
abstract struct AbstractJobType end
struct Soldier <: AbstractJobType end
struct Civilian <: AbstractJobType end
abstract struct AbstractSex end
struct Male <: AbstractSex end
struct Female <: AbstractSex end
struct Person{J,S} where {J<:AbstractJobType, S<:AbstractSex}
job::J
sex::S
end
and then when defining methods you define them somewhat explicitly
info(p::Person{Soldier,Male}) = ...
or something to this effect.
Hopefully someone with more knowledge on this style can clarify or correct this answer.
if you read that you will see a trait system is more likely. Which is understandable as Rust picked up nicely and people already implemented toy Trait system using current type system.
I’m not sure what part of that discussion makes you think that traits are more likely. In my opinion most comments go in the direction that multiple parent types are great but hard to implement and that traits are a limited solution.
Also, why we need to care about Rust decisions in Julia? Are there any interdependencies I’m not aware of between the two projects?
There are no interdependencies or anything of the sort (well both use LLVM but that goes for many others). It’s just that looking at the implementations of others is a nice way to evaluate how they work and what implementations are out there, if there is something very cool out there, it’s always worth it to copy it.
My understanding, roughly speaking, is that Rust is a language created by software engineers for software engineers and Julia is a language created by software engineers for all sort of engineers and scientists. When it comes to languages to draw inspiration from for Julia, in this context, maybe Matlab is more appropriate Subclassing Multiple Classes - MATLAB & Simulink
I think the reason for taking inspiration from Rust is that it is a new language that is considered to be modern and well-designed and using best practices for many things (I personally don’t know much about Rust.)
Matlab, on the other hand, is the language that many Julia users are running away from because it is considered badly designed and outdated, and really horrible to work with, beyond small throw-away scripts (and I do know a bit about Matlab, as I have used it every day for >20 years.)
Taking inspiration from Matlab beyond surface syntax (which is ok) is definitely not something I would like to see.
That’s what I meant (syntax), and in that context I would also advice R. User experience is very important besides well designed internals. Types with multiple parents affect internals but it definitely affects syntax as well.
I though you were advocating taking inspiration from Matlab language design, because it has multiple inheritance. (Multiple inheritance in general is hugely controversial, afaik.)
R? Well, this language I don’t know so well, but everything I’ve heard points to it being pretty far away from Julia design goals.
Multiple Inheritance is also a syntax design, and controversial because it is hard to implement maybe, but if you check the link with the discussion many people like it, including key people in the Julia project.
Internal design absolutely, user experience quite the opposite.
I won’t be to confident here, but my understanding is that it leads to badly designed programs. I’ve never heard it has anything to do with difficulty of implementation, only that it is a bad idea.
Well, this is over a decade ago, and before the language was pre-released. It’s issue number 5 (out of 41700), was it even before the introduction of multiple dispatch?
I think the general opinion long ago moved to preferring traits and composition.
OK, scrolling down on that issue, I see there’s still some discussion, up to a couple of years ago. Anyway, I’ll try not to be too confident, I’ve just always read that “multiple inheritance is bad” as basically a consensus opinion, so I’m a bit surprised that it is seriously considered.
I’m afraid I don’t follow, why should “who the language is designed for” have any bearing on where to draw inspiration/good features from?
Rust is not specifically written for software engineers, it was built to eliminate security related bugs in the (then used) Servo layouting engine (the thing that draws a website in your browser) for Firefox, which originally was C++. Since then it has grown to all kinds of disciplines, mostly systems related, because you literally can’t compile programs with out of bounds memory access unless you use unsafe. It’s grown in features and scope because once C/C++/systems programmers got a taste of a language with a few nice features making their lives easier, we suddenly decided to have our cake and eat it too. In this regard, Rust is not much different from Julia philosophically, we’re just coming at it from a different angle.
Syntax is superficial, it’s semantics that matter. If anything, I doubt the surface syntax of julia would change a whole lot due to the addition of “multiple inheritance”. The issue #5 you linked is by now very old, back then julia looked very different in its 0.2(?) days.
When talking about “inheritance”, there’s (from what I can tell) two main aspects relevant here:
Inheritance of data/layout, which means inheriting fields from supertypes (i.e., allowing concrete type to be subtyped).
Inheritance of behavior, which means allowing a type to match method signatures where any supertype of that type is specified.
The former will, which I’m very confident about, not change. Having only abstract types be inheritable and thus have only concrete types with a data layout makes optimizations regarding code/stack layout easy, makes a lot of data be inlineable etc. This is where “R style” inheritance breaks down, because in that model subtypes do inherit parent properties (which can lead to conflicts and all other sorts of headaches, which should be familiar to people used to that style of inheritance. It’s similar to how inheritance in Java works).
The latter is (to a certain extent) already a thing in julia. When you have a type tree like Any >: AbstractA >: SubAbstractB >: ConcreteC, ConcreteC can already be used in any place where either AbstractA or SubAbstractB is specified. It thus “inherits” the behavior of both AbstractA as well as SubAbstractB. The addition of more multiple behavioral inheritance and the semantics of that is what issue #5 is about, not necessarily how this should be written.
As for traits vs. multiple inheritance - Github has the annoying “feature” of hiding “irrelevant” discussion in issues. I hope you’ve read all of those hidden comments, and not just the part Github shows by default (which misleadingly would give the impression that multiple inheritance in the classic sense is the way to go). For example, in abstract multiple inheritance · Issue #5 · JuliaLang/julia · GitHub there are a few links about more discussion/information/problems that crop up when thinking about this (and why traits will most likely be the way to go), including jeff’s Phd thesis. The discussion in #5 turns to traits as the desirable thing some time after 2014 - looking at how Rust is doing it only follows naturally.
As others have said, the discussion has moved on since, and traits seem like a much better solution.
I think that it would make sense to revisit these old issues periodically, and close them; or at least update them with a summary. Issues older than 5 years usually have a very low probability of being relevant for current priorities.