This post comprises of my notes while reading Luca Cardelli’s 1985 Paper, Semantics of Multiple Inheritance. At the time of writing, a copy of this paper was available for free from ScienceDirect.
These notes are semi-structured, and are intended primarily for my own reflection.
Section 1 -
Cardelli draws a distinction between organizing data in a way “derived from standard branches of mathematics” versus in a way “dervi[ed] from biology and taxonomy”, i.e. Object Oriented programming.
“The notions of inheritance and object-oriented programming first appeared in Simula 67 (Dahl, 1966)”
In OO, “functions and procedures are considered as local actions of objects, as opposed to global operations acting over objects”.
At the time of writing, “the definition of what makes a language object-oriented is still controversial”, but “An examination… suggests that inheritance is the only notion critically associated with [OOP]”
Here’s a statement that excites me:
The aim of this paper is to present a clean semantics of multiple inheritance and to show that, in the context of strongly typed, statically scoped languages, a sound typechecking algorithm exists. Multiple inheritance is also interpreted in a broad sense: instead of being limited to objects, it is extended in a natural way to union types and to higher-order functional types. This constitutes a semantic basis for the unification of functional and object-oriented programming.
Section 2 - Objects as Records
The paper lays out that there are “two … interpretations of objects”. One is “objects as records”; “objects as essentially records with possibly functional components”. Record is only defined in section 3, a “finite association of values to labels”.
The second interpretation “derives from lisp”; an object “if a function which receives a message and dispatches on the message to select the appropriate method”.
“Records can be represented as functions from labels (messages) to values”, however, to say that “objects are functions” is misleading, because we must qualify that “objects are functions over messages”.
Section 3 - Records
The bit at the end of page 5 (in the PDF I looked at, i.e. of the paper, not labeled as page 5) about how typed functions can invert subtype direction is quite interesting.
To get intuitive subtype inclusion, we must define types as “set[s] of all records which have at least the required number of fields of the correct types”. That is, if we define car as having 3 fields, and vehicle as having 2, then for car to be a vehicle we have to use the “at least” rule.
Multiple inheritance in the sense of “and” - as in a thing is a “vehicle and machine” means that the object in question has the required fields of the union of the two types.
Section 4 - Variants
The beginning of this section refers to a “disjoint sum”, This made sense to me after reading this page on chaos.org.uk and this explanation of Disjoint Union from Wikipedia. I believe that a ‘disjoint sum’ is just an element in the disjoint union of the two sets in question.
The trivial type, whose only defined constant is the constant ‘unity’, is called the ‘unit’ type.
An enumeration is a “variant type where all fields have unit type"variant
The rest of this section seems to just lay out that variant types have subtype operators basically the way one would hope and expect.
Section 5 - Inheritance Idioms
The first comment in this section is interesting - it shows that inheritance, as defined so far in the paper, is an implication of definitions, and need not be declared explicitly.
- “Typechecking provides compile-time protection against obvious bugs”
There is a paragraph: “The subtype relation only holds on types, and there is no similar relation on objects. Thus we cannot model directly the subobject relation used by, for example, Omega (Attardi, 1981), where we could define the class of gasoline cars as the cars with fuel equal to "gasoline.” This sounds like the author is talking about “dependent types” as used on the wikipedia page for dependent types.
The next paragraph after that introduces a solution by defining a set of fuel types and then defining “gasoline_car” as a subtype of “car”. My gut is that this sort of compile-time-versus-runtime type-checking (and type-definition?) distinction is related, at some level, to the “code versus data” issue that Lisp (partially?) addresses through homoiconicity.
Interesting note, in that “constructor” is “a vague term indicating that, in an implementation, computation can be temporarily suspended thereby avoiding some looping situations”. This makes me wonder; how does object initialization (construction) work in Ruby?
Possibly to be continued
[Note 2018-05-06] The paper has another 7 sections or so, but I put down and temporarily abandoned process back in December of 2017. I decided to publish these notes anyway, again, mostly for my own reflection and reference.