[PDF] [PDF] Object Inheritance without Classes - Web Home ECS Victoria

It does not support multiple inheritance, but there is a logical extension to do so Constructors have a special role in JavaScript, and must have their prototype 



Previous PDF Next PDF





[PDF] Object Inheritance without Classes - Web Home ECS Victoria

It does not support multiple inheritance, but there is a logical extension to do so Constructors have a special role in JavaScript, and must have their prototype 



[PDF] JavaScript Inheritance and Object Programming - Martin Rinehart

JS Inheritance and OP Prototypes for Methods 79 JSWindows Inheritance 85 Coding OOP Inheritance 86 6 Inheritance Alternatives 91 Multiple Inheritance



[PDF] Module 5 Data Abstraction and Object Orientation:-Encapsulation

In multiple inheritance, a class is defined in terms of more than one existing class Perl and Ruby join Scheme, Python, JavaScript, and R in providing first-class 



[PDF] How Implementation Language Affects Design Patterns - UiO - DUO

ined in the context of the programming languages Python, JavaScript, C#, Go and Multiple inheritance was used in the Python and JavaScript implemen-



[PDF] Creating and using JavaScript objects - IBM

custom-built JavaScript objects and their properties and methods This tutorial inherit the properties and methods of another, and how to alter the structure of an object after In some situations, one property holds multiple pieces of data

[PDF] multiple inheritance means in java

[PDF] multiple inheritance python

[PDF] multiple inheritance swift

[PDF] multiple inheritance typescript

[PDF] multiplexeur et démultiplexeur exercice

[PDF] multiplexeur et démultiplexeur exercices corrigés

[PDF] multivariable unconstrained optimization

[PDF] munich to mumbai lufthansa flight status

[PDF] municipales paris 2020 sondages

[PDF] musculoskeletal system

[PDF] museum of the city of paris

[PDF] music festival expenses

[PDF] music festival marketing campaigns

[PDF] music festival target market

[PDF] music fun let's learn about notes answer key

Object Inheritance without Classes

Timothy Jones

1, Michael Homer1, James Noble1, and Kim Bruce2

1

Victoria Univ ersityof W ellington

2

P omonaCollege Abstract

Which comes first: the object or the class? Language designers enjoy the conceptual simplicity of object-based languages (such as Emerald or Self) while many programmers prefer the prag- matic utility of classical inheritance (such as Simula and Java). Programmers in object-based languages have a tendency to build libraries to support traditional inheritance, and language implementations are often contorted to the same end. In this paper, we revisit the relationship between classes and objects. We model various kinds of inheritance in the context of an object- oriented language whose objects are not defined by classes, and explain why class inheritance and initialisation cannot be easily modelled purely by delegation.

Digital Object Identifier10.4230/LIPIcs.ECOOP.2016.11Intro ductionClass-based object-oriented languages have a simple story about the relationships between

objects and the classes that create them: an object is an instance of a class [2]. A specialised, 'one-off" object is just an instance of a specialised, one-off, anonymous class [15]. Inheritance is between classes, and new objects are constructed and initialised by their classes. This simple story comes at the expense of a more complicated story about classes - especially so if classes are themselves objects. Thirty years ago, Alan Borning identified eight separate roles that classes can play in most class-based object-oriented languages [4], each of these roles adding to the complexity of the whole language, which typically leads inexorably to various kinds of infinite regress in meta-object systems [21, 28, 43]. To address this problem, prototype-based object-oriented languages, beginning with Lieberman"s work inspired by LOGO [32] and popularised by Self [50], adopted a conceptually simpler model in which objects were the primary concept, defined individually, without any classes. Inheritance-like sharing of state and behaviour was handled by delegation between objects, rather than inheritance between their defining classes. Special-purpose objects could be defined directly, while new objects could be created in programs by cloning existing objects. Emerald [3] went one step further and aimed to eschew all implicit sharing mechanisms, supporting neither inheritance nor delegation. Programmers using object-based languages have found the need to reintroduce classes - several times over in many of these languages. The Emerald compiler, and later the Self IDE, added explicit support for class-style inheritance. Languages with object inheritance such as Lua [34], JavaScript [45], and Tcl [51] have a variety of libraries implementing classes in terms of objects. Most recently classes have been added explicitly to the recent ECMAScript standard [52], to bring some order to the profusion of libraries already offering classes. The problem we address in this paper is precisely the tension between the conceptual simplicity of objects and the practical utility of classes: can a language be based conceptually on 'objects first" and include a relatively familiar notion of inheritance? In this paper we present models of eight inheritance mechanisms for a language without an inherent class construct: forwarding, delegation, concatenation, merged identity, uniform identity,

©Timothy Jones, Michael Homer, James Noble, Kim Bruce;licensed under Creative Commons License CC-BY

30th European Conference on Object-Oriented Programming.

Editor: Shriram Krishnamurthi; Article No.1; pp.1:1-1:25

Leibniz International Proceedings in InformaticsSchloss Dagstuhl - Leibniz-Zentrum für Informatik, Dagstuhl Publishing, Germany

1:2 Object Inheritance without Classesmultiple uniform identity, method transformations, and positional inheritance. The first

three correspond to the foundational object-based models, while merged identity and uniform identity introduce more classical behaviour that parallels C++ and Java, and the remaining models introduce multiple object inheritance with different conflict resolution techniques. We evaluate the tradeoffs between power and complexity of these models, particularly in their object initialisation semantics, and compare them to the behaviour of other languages, demonstrating that the typical class initialisation semantics are fundamentally at odds with prototypical object inheritance. We have also implemented all of the models in PLT Redex, making the models executable and allowing direct comparison of the differences in execution for any program.2Inheritance Without Classes The term 'inheritance" typically refers to reuse relationships between classes, but there are also a number of 'objects-first" languages that eschew classes and permit reuse relationships

directly between objects. Consider the following example of an object constructor:methodgraphic {object{methodimage {abstract}methoddraw { canvas.render(image) }varname :="Agraphic "; displayList.register(self); draw}

If we can inherit from this object, what is its behaviour when we do so? Expectations vary for different interpretations of inheritance. We can interpret this method as a factory, and inherit from the fresh object it creates, or assign special semantics to constructor methods and inherit from the method itself. Because of the presence of initialisation code in the class, these interpretations have different - and potentially unexpected - behaviours. In its most basic form, inheritance permits reuse by providing a mechanism for an object to defer part of its implementation to another, already implemented object, but the reality is that there is much more to consider: the value of 'self" in method bodies and during initialisation, intended and accidental method overriding, whether objects are composed of several object identities in an inheritance chain or a single unified identity, the meaning of method requests which are not qualified with a receiver, and so on.

Suppose we create an object which inherits fromgraphic.defamelia =object{inheritsgraphicdefimage = images.amelia;self.name :="Amelia"}

We can draw different conclusions about the state of our program after the creation of this object depending on which inheritance semantics is in play. We can group these into our relevant concerns:Down-calls . Can a method in a super-object call down into a method in a lower object? Can it do so during initialisation? The implementation of thedrawmethod relies on a down-call to theimagemethod.

Jones, Homer, Noble, Bruce 1:3

Registration. Is the identity of a super-object stored during initialisation, either explicitly or through lexical capture, the same as the final object? This is clearly the intention of the call toregisteringraphic"s initialisation.Action at a Distance . Can operations on an object implicitly affect another object? If the registeredgraphicobject is different toamelia, what is the value of itsnamefield afterameliais initialised?Freshness . Can an object inherit from any other object it has a reference to? Does

ameliahave to inherit a call to the constructor, or will a preëxistinggraphicobject suffice?Stability

. Is the implementation of methods in an object the same throughout its lifetime? Whichimagemethod will be invoked by the request todrawat the end of graphic? Can the structural type of an object change after it has been constructed?Multiplicity . Can an object inherit from multiple other objects? Ifameliaalso wished to have the behavior of another object, can a second inherits clause be added? If so, how are multiple methods with the same name resolved, and where are fields located? We are also interested in the general semanticses of the inheritance systems, such as what order the parts of initialisation execute in, what visibility and security concerns arise, and how local method requests are resolved. These are the concerns that we will judge in the following object inheritance models. While ourgraphicexample relies on some of these features to behave correctly, these concerns are not necessarily desirable, and each provides certain abilities or guarantees at some cost. Our intention is to use these concerns to provide an accurate description of the tradeoffs involved with each inheritance model. Some of our models of inheritance attempt to interpret graphicas a class, but only in the sense that it is a factory that guarantees fresh graphic objects. We also compare the models to existing languages which use each form of inheritance, particularly JavaScript, which is capable of implementing all of the models.3Graceless In order to provide a formal semantics for the various object inheritance systems, we first present a base model of the Grace programming language without inheritance, and then proceed to extend this base model in different ways to construct the different behaviours. Grace is a useful language to model object inheritance features in, as it is not class-based, and it does not permit mutation of an existing object"s structure, so we can consider pure object concerns without being overcome by 'open objects" with trivially mutable structure, as found in JavaScript. Our core model resembles the existing Tinygrace language [27], but with more features, such that 'Tiny" is not an appropriate moniker. As the language is still not a complete implementation of Grace, we have opted to name itGraceless. We have modelled object references, mutable and immutable fields, and method requests unqualified by a receiver, in order to demonstrate the wide-ranging effects of changes to the behaviour of inheritance. Explicit types have been removed, in order to focus on the dynamic semantics. The grammar for Graceless is provided in Figure 1. The boxed areas in the grammar represent forms which only exist in the typing judgment or at runtime, not in the user-side syntax of programs. As in Grace, we omit empty argument and parameter parentheses, making some method requests indistinguishable from local variables and field lookups per

Meyer"s uniform access principle [36].

Within an object are method definitionsMand statementsS. A statement is either an expression or a field declaration. Fields are either constantdefinitions orvariable, andvarECOOP"16

1:4 Object Inheritance without Classes

Syntax

S::=defx=e|varx|varx:=e|e(Statement)

M::=methodm(x) {e;e}(Method)

m::=x|x:=(Method name) o::=object{MS}(Object expression) r::=e(Receiver)v::=done|?(Value)

σ::=?|??→ ?F,M?,σ(Object store)

F::=x?→v(Field)

s::=v/x|self.m/m(Substitution)

Evaluation context

E::=[]|E.m(e)|v.m(v,E,e)|m(v,E,e)|E;e|vx←-EFigure 1The grammar of the Graceless base model, with runtime-only components boxedfields may be declared without an initial value.Expressionsein the user-side syntax are object expressionso, method requests either

qualified or unqualified by a receiver, or the sentinel valuedone. At runtime, expressions can also include references?to locations in the heap, sequencese;e, field fetchex-→, and field assignex←-e. The field operations are distinguished from method callse.xande.x:=e. The receivers of the field operations are not holes in the contextE, because we only ever create instances of the operations where the receiver is the termself(which will then be substituted for some actual reference?). Objects can be nested inside of each other (as method bodies) and unqualified requests can be made on the resulting local scope. We assume Barendregt"s rule [1] forselfreferences, such that eachselfvariable introduced by nested object expressions is unique. Because method names appear in the local scope as well as the public interface of their directly surrounding object, we cannot assume Barendregt"s rule that their names are unique - an object may need to shadow an outer object"s method in order to conform to a given interface - so substitution cannot continue past a shadowing definition. Graceless has two forms of substitution. The typical substitution[v/x]ereplaces the termxwith the valuevin the terme. Aqualifying substitution[self.m/m]ereplaces any local requestm(e)with the qualified formself.m(e)in the terme. Both forms of substitution are ended by a shadowing definition, which can be either an adjacent method name or a surrounding parameter definition: substitutions into an object expression[v/x]o and[self.m/m]odo not modifyoif it contains a methodxormrespectively, and the substitutions into a method[v/x]Mand[self.x/x]Mdo not modify the method body if Mhas a parameterx. Because the local variablexand the local method requestxare indistinguishable, the ordering of the substitution is important:[self.x/x][v/x]xproducesv, but[v/x][self.x/x]xproducesself.x. The reduction judgment?σ,e? ?σ?,e??is defined in Figure 2, indicating an expression ewith storeσis reduced to an expressione?with a potentially modified storeσ?. RuleE- Contextuses the evaluation context to perform congruence reduction, and RuleE-Next evaluates to the next expression in a sequence when the current one has finished evaluating. RulesE-Fetch,E-Uninitialised, andE-Assignhandle operations on a field store, with

Jones, Homer, Noble, Bruce 1:5

?σ,e? ?σ,e?(E-Context)

?σ,e? ?σ?,e???σ,E[e]? ?σ?,E[e?]?(E-Next)?σ,v;e? ?σ,e?(E-Assign)?σ,?x←-v? ?σ(?)(x?→v),done?

(E-Fetch)?σ,?x-→? ?σ,σ(?)(x)?(E-Uninitialised) (x?→v)/?σ(?)?σ,E[?x-→]? ?σ,uninitialised?(E-Request) methodm(x) {e}?σ(?)?σ,?.m(v)? ?σ,[?/self][v/x]e? (E-Object) ?freshm=names(M,S)?M f,e?=body(S)?σ,object{MS}? ?σ(??→ ??,[self.m/m]MM f?),[?/self][self.m/m]e;??munique

Auxiliary Definitions

names(methodm(x) {e},S) =m?m fwhere?methodmf(y) {ef},e?=body(S) body(?) =??,?? body(defx=e,S) =?accessors(def,x,y)M,selfy←-ee?whereyfreshand?M,e??=body(S) body(varx,S) =?accessors(var,x,y)M,e?whereyfreshand?M,e??=body(S) body(varx:=e,S) =?accessors(var,x,y)M,selfy←-ee?whereyfreshand?M,e??=body(S) body(e,S) =?M,ee?where?M,e??=body(S) accessors(def,x,y) =methodx{selfy-→} accessors(var,x,y) =methodx{selfy-→}methodx:=(y){selfy←-y}Figure 2Term reduction uninitialisedcrashing the program in any context. The store accessσ(?)(x)looks up the fieldxin the object at location?, andσ(?)(x?→v)sets the fieldxto the valuevin the object at location?, introducing a new field if one was not already present. RuleE-Requestprocess requests by looking up the corresponding method in the receiver. In the method body, it substitutes both the arguments for parameter names, and the receiver for the nameself. RuleE-Objecttakes an object expression and builds a corresponding object in the store, with no fields, the methods in the object expression, and the generated getter and setter methods for the fields. The rule also converts the fields in the object expression into a series of assignments, which ultimately result in the new reference. The internal field names are fresh to avoid having to worry about overridden names under inheritance. Both the methods and the assignments have the relevant qualifying substitutions applied, and the body of the object hasselfbound to the new reference. Note that we could bindselfin the bodies of an object"s methods either in the RuleE- Object(early binding, when the object is allocated) or in RuleE-Request(late binding, when a method is requested). In this model, either choice produces the same behaviour. As we add inheritance to Graceless, our choice to use late binding in the base model will matter: it is trivial to overwrite by also using early binding, but not the other way around.ECOOP"16

1:6 Object Inheritance without Classes

Extended Syntax

I::=inheritses(Inherits clause)

o::=···|object{IMS}(Object expression) s::=···|(?as self)/super(Substitution)v::=···|(?asv)(Value) r::=···|super|(?ase)(Receiver)

Extended Evaluation Context

?σ,e? ?σ,e?(E-Request/Super) methodm(x) {e}?σ(?↑)?σ,(?↑as?↓).m(v)? ?σ,[?↓/self][v/x]e? (E-Inherits) ?F,M ↑?=σ(?)M ?↑=override(M ↑,names(M,S))?σ,object{inherits?sMS}? ?σ,object{M ?↑[s][(?as self)/super](MS)?}

Auxiliary Definitions

override(methodm(x) {e}M,m) =? m?moverride(M,m)

m /?mmethodm(x) {e}override(M,m)Figure 3Object inheritance extension4Object Inheritance We now extend Graceless with various implementations of object inheritance, and consider

the complexity and impacts of the changes. The extensions are presented in a rough ordering of implementation complexity. These represent the three foundational strands of object inheritance: forwarding, as used in E; delegation, as found in JavaScript [52], Lua [25], and Self [50,10]; and concatenation, as in Kevo [47,48] and numerous libraries and idioms for languages with open objects. The extended syntax for object inheritance is given in Figure 3. The extension introduces two new components of user-facing syntax: the bodies of object expressions may now begin with aninheritseclause, and requests can now be qualified by the special variablesuper. These two components each result in a runtime complication. Inheritance introduces the methods from the super-object into the local scope of the inheriting object using an 'up, then out" rule: inherited definitions take precedence over those introduced in a surrounding scope. Because the inherits clause contains an arbitrary expression, we might not know what the names are that the clause will introduce. To counter this, substitutions are delayed by an inherits clause in an object expression: while the substitution will transform the expression in the clause itself, itwill notproceed into the body of the object expression, and gets 'stuck" on the clause instead. Once the expression in an inherits clause is resolved to an object reference, the substitution can proceed into the body of the surrounding object expression, where it may be removed by shadowing. Although there is an explicit super-object in this model of inheritance, making a request tosuperis not the same as making a direct request to the super-object, as the value ofself will be bound to the inheriting object. At runtime, the variablesuperis substituted for a

Jones, Homer, Noble, Bruce 1:7

(E-Object/Forwarding) ?freshm=names(M,S)?M f,e?=body(S)?σ,object{MS}? ?σ(??→ ??,[?/self]([self.m/m]MM

f)?),[?/self][self.m/m]e;??muniqueFigure 4Forwarding modificationsspecial 'up-call" receiver(?as self), which indicates the method to call should be sourced

from the object at location?, butselfin the body of that method should be bound to the eventual value ofselfat the site of the request. The evaluation context has been extended as expected, though we have split the context of an inherits clause into its own formEI, as future models will restrict the evaluation of expressions in these clauses. RuleE-Inheritstransforms an object expression with an inherits clause into one without, by copying the methods from the super-object which are not overridden by a method with the same name into the body of the inheriting object (directly copying the methods has the same behaviour as creating new methods which delegate to the super-object with the same arguments, or searching through a chain of objects for the method, which is representative of typical object inheritance implementations). It also applies the delayed substitutions to the body, after substitutingsuperfor an up-call receiver to the inherited object. RuleE-Request/Supersimply applies an up-call as described. By making subtle modifications to the existing rules in this extended form of Graceless, we can produce models for various implementations of object inheritance. 1

4.1 Forwarding

Under forwarding, inherited methods are simply redirected to the super-object. The super- method receives the same arguments andselfbinding. In the example from earlier, ifamelia receives a request for thedrawmethod, which is not implemented directly inside ofamelia, the request is passed on to thegraphicsuper-object instead. The value ofselfin the resulting invocation is the identity of the super-object: in this example, thedrawmethod crashes, complaining the graphic has not implemented itsimagemethod, because the local request to imagehas been resolved to thegraphicobject and not passed back down toamelia. The modification to the existing Graceless dynamic semantics to implement forwarding is provided in Figure 4. The modification makes one subtle change (highlighted) to the RuleE-Object, by early-binding the value ofselfwhen an object is created in both its methods and field accessors. The result of this change is that the late-binding ofselfin requests (both normal and to super) no longer achieves anything, becauseselfhas already been bound to the object that the method or field originally appeared in. Any forwarded request behaves as though the original object had received the request directly. The value ofselfis always the object a method was defined in, so down-calls are not possible; similarly, the value ofselfduring initialisation is the distinct identity of the super-object, so registration cannot occur then. In this model, an object can only inherit from another before it has run any of its own initialisation, so every object has a stable structure, but one object may be inherited many times. While this model does not permit1

This existing extension of Graceless already implements a form of object inheritance similar to concate-

nation with all fields reset touninitialised, but we do not know of any language with this behaviour,

nor can we see why it would be desirable.ECOOP"16

1:8 Object Inheritance without Classes

(E-Object/Delegation) ?freshm=names(M,S)?M f,e?=body(S)?σ,object{MS}? ?σ(??→ ??,[self.m/m]M[?/self]M

f?),[?/self][self.m/m]e;??muniqueFigure 5Delegation modificationsmultiple super-objects, it would only require updating RuleE-Inheritsto include methods

from multiple inherited objects, with some arbitrary mechanism to resolve multiply-defined methods (such as placing significance on the order of the inherits clauses, or requiring that a multiply-defined method be overridden in the inheriting object). There is no concept of confidential access of methods between implementations, as a forwarded request is sent as a regular request, and so will only be handled by the public interface of the super-object. Forwarding also does not permit downcalls: an inherited object cannot invoke an inheriting object"s method. On the other hand, an object can forward messages to a preëxisting object, and many forwarding objects can share a single target. Inherited fields are shared between all inheriting objects, and the mutation of an inherited field will implicitly affect the super-object and all of its heirs. In the E language, there is no explicit self reference, as all object definitions are explicitly named. The authors of E refer to the language"s inheritance mechanism as "delegation", but

in the absence of self references the behaviour aligns with what we have called forwarding.defgraphic {todraw() { canvas.render(graphic.image()) } }defameliaextendsgraphic {toimage() { images.cat() } }

Even thoughameliadefines a methodimage, the call indrawclearly looks for the method in thegraphicobject. Methods cannot be requested on the local scope, so the receiver must always be explicit. In order to achieve down-calls, the inheriting object must explicitly be passed to the super-object, which is a standard pattern for simulating class behaviour in E.

4.2 Delegation

Delegation is an implementation of object inheritance that aimed to be at least as powerful asquotesdbs_dbs20.pdfusesText_26