A Reflective Framework
Total Page:16
File Type:pdf, Size:1020Kb
Chapter 55 A Reflective Framework 5.1 Introduction Now that we have defined an open design for object-based and object-oriented programming languages, we can focus on how to turn this open design into a reflective system. Turning an open design into a reflective system differs in a fundamental way from the conventional approach of defining reflective languages. Conventionally a reflective language is defined by giving a meta-circular interpreter for it. This meta-circular interpreter can contain various circularities that are resolved by imagining an entire tower of meta-circular interpreters. In an actual running system various mechanism are used to implement this tower. Resolving these circularities is an essential step in making a running reflective language. We will take another approach. As we said in the chapter on reflection a programming language is turned into a reflective one by extending it with reflection operators. We will consider those open designs that are powerful enough so that reflection can be added as a full-fledged specialisation of the open design. The advantage is that in that case a formal relation exists between a reflective language and its open design. Reflection is added as an orthogonal language concept. Among others this means that the open design itself (meta- circularly defined or not) does not need to be altered in an ad hoc fashion to turn it into a running reflective system. As discussed in the chapter on reflection, turning a system with an open design in a reflective system is a matter of 1) achieving a symbiosis of the implementation language of the open implementation and the engendered language, and 2) providing the necessary reflection operators that may or may not avoid reflective overlap. Our discussion will follow these steps. Chapter 5 A symbiosis between two object-oriented languages enables objects to freely travel from one language to the other. First we will show how an object-oriented language can achieve a symbiosis with its underlying object-oriented implementation language. We will also show that this can be done with a fairly general mechanism. A symbiosis between an object-oriented programming language and its implementation language will be achieved by the introduction of conversion-methods and objects that incorporate reflection equations. The properties of these will be discussed. In practice, the choice of the reflection operators is an important issue. Reflection operators must give access to both the base- and meta-level interface of the meta- system. A fully reflective language must give access to the entire base- and meta- level interfaces. We will discuss different sets of operators each with different characteristics, and show that to a certain degree, making a choice between them is a matter of taste. Exactly as discussed, both the linguistic symbiosis and the reflection operators are added to the framework as an extra layer, i.e. reflection operators are in some sense not different of any other extension of the framework that adds new sorts of expressions and new sorts of objects. In fact the extension of the framework with reflection involves extending the framework's object hierarchy (with conversion objects that realise the symbiosis) and the expression hierarchy (with the actual reflection operators). 5.2 Object-based Reflection 5.2.1 Linguistic Symbiosis Both Agora and its implementation language are object-oriented languages. The purpose of this section is to show how objects from Agora's implementation language can be used as Agora objects, i.e. how messages, expressed in Agora, can be sent to implementation language objects. Vice versa, we will show how Agora objects can be used as objects from the implementation language, i.e. how messages, expressed in the implementation language, can be sent to Agora objects. This is depicted informally in the following figure. 166 A Reflective Framework Implementation Language Agora m n m n Implementation Object Agora Object Implementation Object Agora Object Representant for Representant for Agora Object Implementation Object m Implementation Message m Agora Message n Resulting, Mixed Message Figure 5.1 Before plunging into the technical details of the symbiosis of Agora and its implementation language, we will need some terminology. The distinction between Agora objects and implementation level objects will be blurred because after the symbiosis, objects will be able to travel between Agora and its implementation language. The simple terminological difference between Agora objects and implementation level objects is not good enough anymore. Therefor we will need a new terminology. The point is that we will need to make a distinction between the language in which an object is expressed and the language from which messages can be sent to an object. First of all we can make a distinction between implicit messages — messages expressed in the implementation language — and explicit messages — messages expressed in Agora. Secondly we will talk about an explicitly encoded object when this object is expressed in Agora, and about an implicitly encoded object when this object is expressed in the implementation language. Not every explicitly encoded object need to be referenced from within an Agora program. An object that can be sent implicit messages is called an implicitly referable object, an object that can be sent explicit messages is called an explicitly referable object. Finally we will simply talk about an implicit (explicit) object when this object is both implicitly (explicitly) encoded and referable. The following table summarises our terminology. 167 Chapter 5 Implementation Language Agora referable Implicitly Referable Object Explicitly Referable Object encoded Implicitly Encoded Object Explicitly Encoded Object referable & Implicit Object Explicit Object encoded Figure 5.2 For one particular kind of objects this terminology can be interpreted in an ambiguous way. This is the source of much terminological confusion in object- oriented reflective programming languages. A meta-object is an object that is both implicitly and explicitly referable, albeit with two different protocols. To illustrate this, let us have a look at how explicit objects are represented in the implementation language. Each explicit object is represented at the implementation level by an implicitly referable meta-object. The latter will be called the representation of the former, the former will be called the referent of the latter. An explicit message to an explicit object is represented (or implemented) by an implicit message to the implicitly referable representation of that object, albeit a message with a different signature. Implementation Language Agora has as Referent (reF) has as Representation (reP) send:#m m m Explicit Message Meta-Object m Implicit Message Figure 5.3 If the relation 'reP' associates each explicit object with its representation object, and the relation 'reF' associates each meta-object with its referent object, then the following holds for message passing between objects (depicted in the next table). Pattern objects are conveniently represented as '#x:y:z:', and argument lists as '{a1, … an}'. 168 A Reflective Framework Agora Objects and Their Representations (rule 1a) reP[o x1:a1 x2:a2 … xn:an] = reP[o] send:#x1:x2:…xn: client:(StandardClient private:{reP[a1], … reP[an]}) if o, a1, a2, … , an are explicitly referable objects, and o x1:a1 x2:a2 … xn:an is an explicitly sent message Meta-Objects and Their Referents (rule 1b) reP[ reF[mo] x1:reF[ma1] x2:reF[ma2] … xn:reF[man] ] = mo send:#x1:x2:…xn: client:(StandardClient private:{ma1 … man}) if mo, ma1, ma2, … , man are implicitly referable meta-objects, and mo send:(…) client:(…) is an implicitly sent message Equality of Referents and Representations (rule 1c) reF[mo1] = reF[mo2] ⇔ mo1 = mo2 reP[o1] = reP[o2] ⇔ o1 = o2 if mo1, mo2 are implicitly referable meta-objects, and if o1, o2 are explicitly referable objects Notice that it can be proved that the relations reF and reP are in a sense inverse relations with respect to message passing. It can be shown that an explicit message sent to 'reF[reP[o]]' has the same effect as an explicit message sent to 'o'. reP[ reF[reP[o]] x1:reF[reP[a1]] … xn:reF[reP[an]] ] = (rule 1b) reP[o] send:#x1:x2:…xn: client:(StandardClient private:{rep[a1] … reP[an]}) = (rule 1a) reP[o x1:a1 … xn:an] therefore (rule 1c) reF[reP[o]] x1:reF[reP[a1]] … xn:reF[reP[an]] = o x1:a1 … xn:an Conversely it can be shown that an implicit 'send:client:' message to 'reP[reF[mo]]' has the same effect as an implicit 'send:client:' message to 'mo'. reP[reF[mo]] send:#x1:x2:…xn: client:(StandardClient private: {reP[reF[ma1]], … , reP[reF[an]]}) = (rule 1a) reP[ reF[mo] x1:reF[ma1] … xn:reF[man] ] = (rule 1b) mo send:#x1:x2:…xn: client:(StandardClient private:{ma1 … man}) Returning to the question of how to construct a symbiosis, we can now consider two conversion methods for implicitly referable objects. The first — named 'asImplicit' — turns a meta-object into an implicitly referable object with the protocol of the referent of the meta-object. The second — named 'asExplicit' — turns an arbitrary implicitly referable object into a meta-object, i.e. into a representation of an explicitly referable object with the same protocol as the initial implicitly referable object. Note that these conversion methods are implementation level methods, i.e. they can only be sent at the implementation 169 Chapter 5 level. The two conversion methods are illustrated in the following figure. Implementation Language Agora m Making Explicit (result of applying asExplicit) has as Referent (reF) n Making Implicit m (result of applying asImplicit) has as Representation (reP) n Implicit Object Explicit Object Representant for Representant for Implicitly Referable Explicitly Referable Explicitly Encoded Object Implicitly Encoded Object m Meta-Object Explicit Message m Implicit Message n Resulting, Mixed Message Figure 5.4 These conversion methods are crucial in achieving a symbiosis between Agora and its implementation language.