
What Shall We Tell the Children (About Inheritance)? Andrew P. Black Portland State University [email protected] Abstract Thus wrote Cook and Palsberg, in their 1989 OOPSLA pa- per “A Denotational Semantics of Inheritance and its Cor- Since the groundbreaking work of Kamin, Reddy, and par- rectness” [7]. That paper goes on to tell a story about the ticularly Cook in the late 1980s, there has been broad agree- meaning of inheritance that has become broadly accepted as ment that the meaning of inheritance in object-oriented pro- the standard semantics. Working independently, Kamin [12] gramming languages can be best explained using generator and Reddy [15] had previously published their own seman- functions and their fixpoints. Consequently, it is a little sur- tics, which are broadly similar. (Kamin’s is less composi- prising to realise that no current mainstream programming tional because it involves taking fix points over the whole language actually explains inheritance to its users in this program, rather than individual class generators.) way. Instead, most languages make up a “story” that pur- This paper does not contain any new results. It’s goal is ports to explain inheritance, but that on closer inspection to explain to you, the reader, as clearly as possible what you contains serious flaws. It is as if, being asked to explain the probably already know: how inheritance works. We look at facts of life to our children, we are so embarrassed by the operational and denotational definitions of inheritance, and truth that we make up a story about storks, knowing even notice where they differ. We consider the complexity that is as we do so that it defies the laws not only of biology but unexpectedly introduced by an apparently simple concept: also of physics. This paper explores both the truth and the immutable objects. Finally, we consider the question in the fictions about how objects are brought into the world. My title: what shall we tell the children about inheritance. Is the hope is that future programming languages can tell the chil- typical object-oriented programmer ready to hear the truth dren, if not the whole truth, then at least a partial truth that about the facts of life? Or should we continue to make up is consistent with the laws of mathematics. stories full of fictions and half-truths? I am interested in these issues because I am involved in Categories and Subject Descriptors D.3.3 [Programming designing a new programming language called Grace [5], Languages]: classes and objects; inheritance which aims to be an “as simple as possible” language for teaching object-oriented programming to computer scien- General Terms Languages, Design tists. Because the target audience comprises novice program- mers, we want to introduce no more concepts than necessary, Keywords inheritance semantics, object initialisation, im- but because they will, we hope, become computer scientists, mutable objects we want those concepts to conform to the laws of logic and mathematics, and not be things that will have to be “un- learned” later. My point of view is that it’s OK for novices 1. Introduction computer scientists not to be told the whole truth; it’s not OK Inheritance is one of the central concepts in object- to tell them outright falsehoods. I agree with the late John oriented programming. Despite its importance, there Reynolds in believing that for this we should be convicted seems to be a lack of consensus on the proper way to of moral turpitude and have our tenure revoked [16]. describe inheritance. 2. How Objects Work Many languages don’t allow objects to exist unless they Permission to make digital or hard copies of all or part of this work for personal or have been generated by a class. This “classes first” approach classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation constrains the teaching sequence, and makes it harder to on the first page. To copy otherwise, to republish, to post on servers or to redistribute introduce objects to students. to lists, requires prior specific permission and/or a fee. MASPEGHI 2013 Montpellier, France Grace follows a few other languages, starting with Emer- Copyright © 2013 ACM 978-1-4503-2046-7/13/07. $15.00 ald [4], and including Reddy’s ObjectTalk calculus [15], OCaml [13] and Scala [19], in providing stand-alone ob- Square brackets are used to build a new environment by jects that are independent of any class. A Grace object is adding a list of bindings to an existing environment; ρ0 is very simple: it is a mapping from method names (seman- the empty environment. Methods are functions that take a tically, elements of an arbitrary index set) to method bod- list of arguments ~a, and return the meaning of the expression ies. A method body is a “parameterised behaviour”, that is, in the method body. (This will usually be a function from a parameterised expression whose evaluation can have ef- a store to a pair consisting of a store and a value, but for fects. The act of “sending a message” to an object, which in our purposes, it doesn’t really matter.) Here, the method Grace we call “requesting a method” of the object, involves body meaning is determined in an environment in which the parameterising the method using the arguments provided in method’s parameters are bound to its arguments, and self is the method request, and evaluating the method body. bound to the parameter to the generator function. Here is a point object in Grace syntax. It’s fine to have two explanations of something, so long as def point34= object { they correspond. As Cook and Palsberg [7] showed, the op- method x{3} erational and denotational definitions do mostly correspond, method y{4} but notice one place in which they differ. The operational method magnitude{ definition binds self when a method is requested, whereas the ( self.x^2 + self.y^2 ).sqrt} denotational definition binds self when the object is created. method isSmaller(p) { Specifically, this means that there is no way that the denota- self.magnitude<p.magnitude tional definition can allow the isSmaller method from point34 } } to be “reused” in some other object. Such reuse would re- quire an “unbound” self that could be “rebound” after reuse, It’s an immutable object, so it doesn’t need “instance vari- but the denotational semantics states that self is bound at the ables”; we could give it “instance constants”, but we won’t time that the method suite for point34 is created. In contrast, bother with this detail here. Apart from the basic syntax — the operational definition — along with most implementa- that def defines a name, that object constructs an object, that tions — binds self when a method is requested. method introduces a method, and that . and the operator sym- bols request methods — there is one thing here that needs Reasonable people may disagree on whether the denota- careful explanation: self. tional view is actually a falsehood, or just incommensurable with the operational view. We will return to this point in Sec- We can explain self operationally or denotationally. The tion 4. operational explanation is that self refers to “the message receiver itself” [10, p. 50]. Whenever a method is requested of an object, a reference to that object is pushed onto the 3. Adding Classes execution stack; self means the object thus referenced [10, As soon as we consider adding classes, we must confront p. 603–4]. Consequently, when p.magnitude is executed, a the question: for what purpose? In a classic paper, Borning reference to p is pushed, and any occurrence of self in p’s [6] lists eight roles played by classes in Smalltalk. Primary magnitude method thus refers to p. amongst these roles is generating new objects, so we will The denotational explanation says that self is the object look first at how to support that role. We have already seen created by the object constructor in which it is statically how to generate a single object, using an object constructor. nested. More formally, an object is a mapping from method It is easy to create an object that plays the object generation names to method bodies; the environment in which the role of a class; we need only wrap an object constructor in a method bodies are interpreted is the syntactically-enclosing method, like this. environment, augmented by bindings for the method’s pa- def pointFactory= object { rameters and for self. To actually build this mapping, the method x(xcoord)y(ycoord){ object constructor must build a generator function: a func- object { tion from objects to objects. The object that we want is the method x{ xcoord} fixpoint of this function. If we assume that an object dec- method y{ ycoord} laration does not have a side-effect on the state, we can } paraphrase and simplify Reddy’s formulation [15], to get: method magnitude{ ( self.x^2 + self.y^2 ).sqrt [[object fmethod mi(~pi)feigg]] η = } method isSmaller(p){ fix(λs. ρ [m 7! 0 i self.magnitude<p.magnitude (λ~a: [[ei]](η[~pi 7! ~a; self 7! s]))]) (1) } } th Here, mi is the name of the i method, ~pi its parameter list, } and η the environment surrounding the object constructor. } I’m going to refer to objects like pointFactory as factory It should now be clear that to serve as a basis for in- objects, to emphasise that their role is to create new “in- heritance, a class needs to contain a version of the inheri- stance” objects: they intentionally do not fulfil many of the table methods in which self remains unbound.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages9 Page
-
File Size-