Deep dive detangling terms: multiple inheritance vs. traits

I did not read issue 5, I am just expressing my view on this subject.

I don’t agree with this use of the phrase “multiple inheritance”. In PL theory, traits and inheritance are separate concepts, though they can be used to similar ends.

Note that the Wikipedia page for traits even expliclty says " …an object defined as a trait is created as the composition of methods, which can be used by other classes without requiring multiple inheritance."

Yes, exactly, traits are much more Julian, and they can accomplish everything that multiple inheritance can.

I would not glorify this part of CS with the term “theory”, it is a more-or-less systematic descriptive classification of what some programming languages happen to do.

Specifically, a lot of this terminology is specific to and makes sense only for C++ & friends.

Yes, but traits as currently described in the manual are still a special case. The generic form is possibly

# each gx computes a value of a small, preferably singleton, type
f(args...) = _f(g1(args...), g2(args...), ..., gN(args...), args...)

_f(t1::T1, t2::T2, ..., tN::TN, args...) = specific_code for T1, T2, ..., TN

One can do multiple layers of this and handle complex dispatch patterns in a very efficient manner.

1 Like

Those wikipedia pages are omitting the giant disclaimer “in object oriented programming languages” and also omit the classical meaning of “multiple inheritance”, meaning inheritance of both behavior and structure/fields (which I’ve deliberately seperated in my post above…). I’m talking about how those concepts translate to julia, where abstract types are most commonly used for defining an interface/set of methods to implement for concrete types. In that context, “subtyping” more than one abstract type is akin to “inheriting” multiple “behaviors” (as in, being able to be passed into two different methods expecting either of the subtyped abstract types).

All this is explained and debated in the various comments in issue #5 (including comments hidden by githubs anti-feature) - I really encourage you to read through it before continuing this discussion.

This is quite insulting. The mathematical foundations of programming languages (and computational theory more broadly) have been extensively studied for nearly a century. I have no idea what you think would justify this statement.

What I said above — the “theory” for OOP and related concepts (multiple inheritance, etc) is basically a description of what OOP languages happened to do.

Yes, you can introduce math formalism for it and maybe rationalize it from first principles (people tried that in the 1970s and 1980s), but it does not make it a “theory” with much content beyond the actual language spec. (Which is fine — not everything needs to be a theory).

OOP has been around for 40–50 years in practice, depending on how you count.

These are facts, I am not sure why you consider them insulting.

This is simply not true. But I am not going to discuss this further here, as it would be out of scope.

I will take a look at issue 5, if I have time, and I will comment again if there is anything to add.

Note that this is harshly distinct from what “PL theory” (as thought of in formal circles in the context of formalizing programming languages) refers to. I think there’s some confusion between terms here.

As for my comment/interpretation about how traits and abstract types in julia interact with the term “multiple inheritance”, I’d like to refer you to Bjarne Stroustrup:

Multiple Inheritance is the ability of a class to have more than one base class (super
class). In a language where multiple inheritance is supported a program can be structured
as a set of inheritance lattices instead of (just) as a set of inheritance trees. This is widely
believed to be an important structuring tool.

This was the first “formal” reference to multiple inheritance, if I’m not mistaken. Earlier references are

  • Bjarne Stroustrup:
    What is ‘‘Objet-Oriented Programming?’’.
    Proc. ECOOP,
    Springer Verlag Lecture Notes in Computer Science, Vol 276, June 1987
  • Bjarne Stroustrup:
    The Evolution of C++: 1985-1989.
    USENIX Computing Systems Vol 2 no 3, Fall 1989

which are both descriptive works (the former of OOP languages at the time of writing, the latter of C++ itself), not exploratory theory.

This definition applied to julia leads us exactly where I pointed to: seeing abstract types as a collection of methods to implement and allowing multiple supertypes leads to multiple inheritance (of behavior only). All inheritance of structure and fields is slapped onto this because traditionally this is only done in OOP languages, most of which did not make the decision of only allowing leaves (well, concretely type leaves) in the type tree to have fields.

Or, how Rust puts it:

A trait is a collection of methods defined for an unknown type: Self

It’s not quite the same, since Rust doesn’t have a type tree like julia does, but the concepts are similar enough.

The distinction in the case of julia is that these collections of methods are not enforced on the compiler level to be implemented for subtypes because of the dynamic nature of julia. Having multiple inheritance of abstract types combined with (debatably) enforcing existance of methods for subtypes would be quite enough to have “traits” in julia, so I’ll stand by my point: “true” julian traits are a kind of multiple inheritance.

1 Like

There is no such distinction. Programming languages have a one-to-one correspondence with formal logic, more specifically intuitionistic logic in the case of non-Turing complete languages and classical logic in the case of (more common) Turing-complete languages. OOP concepts such as inheritance and polymorphism can be interpreted under the same type theories that underpin formal languages and functional programming. The trouble with OOP is that the coupling of behavior and data structure makes such theoretical interpretation difficult (and also happens to translate to practical difficulties as well).

seeing abstract types as a collection of methods to implement and allowing multiple supertypes leads to multiple inheritance (of behavior only)

I understand your point that, in Julia, types inherit behavior only (although this is not enforced, as you later point out). I absolutely agree that this would prevent Julia from inheriting (pun intended) many of the pathologies of multiple inheritance in OOP languages. I also agree now, after some more thought, that multiple abstract inheritance in this way could, in some sense, provide trait-like behavior.

I am not convinced that this is the most Julian approach to supporting traits, though, since this would require the type definition to be modified in order to formally implement a trait. Something more akin to Julia’s current trait-hack but both syntactically and semantically implemented in the compiler (most notably in dispatch) seems preferrable to me.

I still think that “inheritance” is the wrong concept here. Julia’s core concept for organizing code is multiple dispatch, which relies on the subtype relation (among other things, most importantly parametric types).

If a method has abstract types in its signature, then it will apply to subtypes, otherwise it won’t.

That’s all there is to it, really. These are building blocks, and it is up to the programmer to build something meaningful out of them.

Sure, but this is an ex post description of what programming languages happened to do (this was pretty much my point above). A formal notation was developed for these concepts, but is unclear how it “underpins” languages used in practice — there were here first (I am of course not talking about languages used for research and teaching).

Also, this theory is not generative in a practical sense: it is great for mathematical proofs and formalized descriptions, but does not tell you how to create a nice programming language that is practically useful for organizing code. Consequently, its relevance for discussions about new and existing features of Julia is somewhat limited (clarification: I am talking about the user’s perspective, not the implementation; for the latter theory can of course be useful).

I still think that “inheritance” is the wrong concept here

I agree. That was kind of part of my original point, but @Sukera insisted on describing it as “multiple inheritance”, and this is correct in the sense that concrete types do “inherit” any functions implemented on their abstract parent types.

It is quite common in science for practice or engineering to precede theoretical description. This is not specific to CS or programming. Your comments make it sound like the theory was simply a description of arbitrary decisions made by programming language designers. This is simply not true.

It’s fine to be practice-oriented, and you’re right that sometimes theory doesn’t translate into practical coding principles (see Haskell). But this is no reason to dismiss theoretical investigation outright as purely descriptive or academic. Better theoretical understanding certainly can lead to better, more consistent, and more expressive programming languages.

1 Like