0. Intended Use
Emerald is an object-oriented programming language designed for thedevelopment of distributed applications (although it can also be used forgeneral-purpose programming).
1. Basic Concepts
Emerald is a strongly-typed object-oriented language. All entities inEmerald are objects. This includes small entities, such as Booleans andintegers, and large entities, such as directories and compilers. All objectsexhibit uniform (object) semantics even though they may be implementedwith different techniques. Objects are the units of programming and distribution,and the entities between which communication takes place. An object canbe manipulated only through invocation of its exported operations; no externalaccess to an object's data is permitted. Operations can be invoked on non-local(in the network) objects, and objects can move from node to node. [BHJL86]
Each Emerald object has four components:
1. A name, which uniquely identifies the object within a distributednetwork
2. A representation, which consists of the data stored in theobject. The representation of a programmer-defined object is composed ofa collection of references to other objects.
3. A set of operations, which define the functions and proceduresthat the object can execute. Some operations are exported and may be invokedby other objects; others are private and may only be invoked by the containingobject.
4. An optional process, which operates in parallel with invocationsof the object's operations. An object with a process is active andexecutes independently of other objects. An object without a process ispassive and executes only as a result of invocations.
An Emerald object also has several attributes. An object has a locationthat specifies the node on which the object is currently resident. Emeraldobjects can be defined to be immutable; this simplifies sharingin a distributed system, since immutable objects can be freely copied.Immutability is an assertion by the programmer that the abstract stateof an object does not change; it is not a concrete property, and the systemdoes not attempt to check it. [BHJL86]
See entry under 2.9 communication model for an example objectdefinition.
Emerald supports concurrency both between objects and within an object.Within a network many objects can execute concurrently. Within a singleobject, several operation invocations can be in progress simultaneously,and these can execute in parallel with the object's internal process (ifit has one). To control access to variables shared by different operations,the shared variables and the operations manipulating them can be definedwithin a monitor [Hoa74]. Processes synchronize through built-incondition objects. An object's process executes outside of the monitor,but can invoke monitored operations when it needs to access shared state.[BHJL86]
See entry under 2.9 communication model for an example objectdefinition.
2.4 specification of behavioral semantics
2.7 object lifetime
See 6. Identity, Equality, Copy
2.8 behavior/state grouping
2.9 communication model
Emerald supports concurrency, in the form of active objects.An active object contains a process that is started after the object isinitialized, and executes in parallel with invocations of the object'soperations, and with the executions of other active objects. This processcontinues to execute its specified instructions until it terminates. AnEmerald process represents an independent thread of control. New threadsmay be created dynamically by creating new objects.
In Emerald, operation invocation is synchronous. Thus, a thread of controlcan be thought of as passing through other objects when it invokes operationson those objects. This means that there can be multiple simultaneous invocationsof an operation in the same object. Each such invocation can proceed independently.
Emerald uses monitors to regulate access to local state thatis shared by the object's operations and process. Synchronization is achievedusing system-defined condition objects [Hoa74]. [RTLB+91]
The following example illustrates various aspects of Emerald with asimple implementation of a clock. The objects in the example are createdusing Emerald object constructors, denoted by the keyword object(see entry under 5. Encapsulation for a description of object constructors).The clock object uses a simple internal representation (theTime)that is protected by a monitor and can be manipulated by several monitoredoperations. The internal representation is constantly updated by the clockobject's process, which synchronizes with a timing pulse provided by thesystem object. The operations for converting between the internal and externalrepresentations are defined outside the monitor, thus allowing multiplesimultaneous invocations of them to proceed concurrently. The Systemobject demonstrates a simple use of Emerald condition objects to providebuffering of timing pulses. [RTLB+91]
const Clock <- object C export getTimeOfDay, setTimeOfDay monitor var theTime: Integer <- 0
operation IncTime theTime <- theTime + 1 end IncTime
function getTime -> [r: Integer] r <- theTime end getTime
operation setTime [r: Integer] theTime <- r end setTime end monitor
operation setTimeOfDay[newTime: String] var t: Integer % store newTime in some internal form setTime[t] end setTimeOfDay
operation getTimeOfDay -> [currentTime: String] var t: Integer <- getTime % return the String form of t end getTimeOfDay
process loop System.Tock IncTime end loop end process end C
const System <- object S monitor const timing <- Condition.Create
% Tick is invoked by a hardware clock operation Tick signal timing end Tick
operation Tock wait timing end Tock end monitor end S
In Emerald, objects conceptually do not share implementation, and thereis no notion of implementation inheritance. Hence, in Emerald the choiceof a method to be executed in response to a request is limited to the singleimplementation of the operation contained in the object.
Emerald supports a number of forms of polymorphism. In Emerald, alloperations are naturally polymorphic (i.e., work "correctly"regardless of the types of their arguments) because objects (of differenttypes) may be used as arguments provided they conform to the typesdeclared for the formal parameters of the operation (a form of inclusionpolymorphism). See entry under 7. Types and Classes, for a discussionof conformity. Emerald supports user-defined operations that return types(type objects), subject only to the constraint that the types of variables,constants and formal parameters be evaluable at compile-time. Since typesare objects, types may be passed as arguments to functions that createtypes (i.e., parameterized type constructors). This is a form of parametricpolymorphism. Objects in Emerald are also polymorphic, in the sensethat they can be used in situations requiring different types; e.g., anobject can be assigned to any identifier provided that the object's typeconforms to that declared for the identifier.
Object creation in Emerald is done via an object constructor,an Emerald expression that, when evaluated, creates a new object. Thisexpression defines the object's representation, and its public and privateoperations (an example is given in 2.9 communication model). Thesyntax of an object constructor is:
object anObject % private state declarations % operation declarationsend anObject
An export clause liststhe operations that can be called from outside the object; invocation ofone of these operations is the only way in which a client can examine ormodify the object's state. [RTLB+91] An object has only one interface,in the sense that there are no constructs that have special access to theobject. However, as noted under 7. Types and Classes, a client accessingan object via a variable will be restricted to performing the operationsdefined by the abstract type of the variable, even though the object assignedto the variable may support additional operations. In such cases, the variable'stype may in some sense be viewed as defining a different interface to theobject.
6. Identity, Equality, Copy
In Emerald, each object has unique identity. The representation of thisidentity depends on the object's implementation (see entry under 9.6other for a description of Emerald's object implementation styles).To support remote referencing and mobility in a distributed system, objectreferences must be location independent. Direct objects are compiledinline or allocated directly in invocation records, and hence can be referencedby offset within the object or data structure. All other objects are referencedby the address of a node-local object descriptor. The object descriptorcontains the object's unique ID, a location hint if the object is remote,and a pointer to its data area, process, and code if the object is locallyresident. An object descriptor must exist on a node as long as any referencesto the corresponding object remain on that node. Object descriptors areheap-allocated and garbage collected.
Each node also has an object table that contains an entry forevery remotely referable object on that node. The object table is usedto determine if an object exists on a node, and if so to provide the addressof its object descriptor. [BHJL86]
7. Types and Classes
Emerald's type system reflects its intended use in the development ofsoftware in constantly running distributed systems. In such systems, objectsmay be developed and implemented separately and differently on differentmachines at different times. Moreover, to accommodate situations wherethe types of the objects to be bound to an identifier are not known atcompile time, the Emerald type system does not distinguish between objectsbased on their implementation.
An Emerald abstract type is a collection of operation signatures,where a signature consists of the operation name and the types of the operation'sarguments and results. A type contains no information about implementation;it only describes an interface. An example of a simple type declarationis:
const Printable <- type Printable function asString -> [String] end Printable
Each identifier in an Emerald program, including the names of constants,variables, arguments, and results, has a declared type, which must be evaluableat compile time; this is called the syntactic type of the name.For example, using the above type declaration, one might define a variablevar aPrintableObj: Printable.Type checking in Emerald is the process of ensuring that the object towhich a name is bound always satisfies the syntactic type of the name.The precise definition of "satisfies" in this context is givenby the conformity relation. If an object O is bound to a name I,then the abstract type of O must conform to the syntactic type ofI.
The motivation behind Emerald's definition of conformity is the notionof substitutability. Informally, an abstract type S conforms to an abstracttype T (written S o> T) if an object of type S can always be substitutedfor one of type T, that is, the object of type S can always be used whereone of type T is expected. For S to be substitutable for T in this wayrequires that
1. S provides at least the operations of T (S may have more operations)
2. For each operation in T, the corresponding operation in S has thesame number of arguments and results.
3. The types of the results of S's operations conform to the types ofthe results of T's operations.
4. The types of the arguments of T's operations conform to the typesof the arguments of S's operations. (Note the reversal in the order ofconformity for arguments).
Property 4 is known as contravariance (property 3 is known ascovariance). The idea behind contravariance is that an operationon objects of a given type should also work on objects of subtypes of thattype.
Each Emerald object may belong to several abstract types because anobject O belongs to an abstract type T when typeofO o> T. The application of typeofto an object returns its maximal type, that is, the largest Emeraldtype that the object can belong to. [RTLB+91]
Emerald's approach to typing allows the use of any object that can handlea given set of messages (satisfies an interface) in a context that sendsjust those messages (requires that interface), independently of how thosemessages are implemented within the object. It also allows both the requirementsof clients and the capabilities of objects to be expressed abstractly,in terms (respectively) of the required and provided interfaces, withoutbeing bound to specific combinations of operations that object implementorshave chosen to implement, or that are defined in existing type specifications.Moreover, it permits these advantages to be obtained while retaining theability to perform strong type-checking.
The conventional approach to defining subtype relationships among typesis to explicitly declare them. However, the conformity relation used inEmerald instead creates implicit subtype relationships among definedtypes, and, in fact, induces a lattice on those types (the top of thislattice is the predefined type Any,which has no operations). Any type that supplies the interface requiredby type T is implicitly a subtype of T, and may be used as such. Thus,conformity allows the introduction of new supertypes into a type latticewithout having to modify the definitions of existing types (or the structureof the type lattice). Emerald provides no means for explicitly declaringthe conformity relation (e.g., for explicitly declaring that one abstracttype is a subtype of another). Instead, this is determined by comparingthe operation signatures defined for the types. This can lead to "mistaken"type matches when two types that are not semantically related happen tohave the same operation signatures. Such problems can be reduced by includingoperations in the types that are specific to the type defined.
Emerald has no notion of class; Emerald provides object constructorsfor run-time creation of objects. An object constructor is an Emerald expressionthat, when evaluated, creates a new object. Object constructors performthe following subset of the functions carried out by classes in a languagesuch as Smalltalk:
1. They generate new objects.
2. They describe the representation of objects.
3. They define the code that implements operations. [RTLB+91]
A number of similar objects can be created by placing an object constructorwithin a loop, or within the body of an operation of another object. Thisallows for the definition of "factory objects" if that is desired.
The Emerald compiler generates templates that describe the structureof each object. Code and templates are stored in kernel structures calledconcrete types. One concrete type exists for each object constructor.Concrete types are immutable, and copies of them may exist on many nodes.When an object is moved to another node, the concrete type is not sentalong; it is requested by the target node only if needed. Concrete typessupport the sharing of structure information and operation code among objectsconstructed using the same object constructor. As a result, to a certainextent concrete types resemble classes from an implementation point ofview. However, concrete types are apparently not visible at the Emeraldlanguage level, but are instead considered part of the language implementation.
Locating the code for an invoked operation is simplified by the Emeraldtype system. The abstract type of a variable specifies the operations thatcan be performed on the object it names. At run time, the variable referencesan object with a specific concrete type. Even though the object may havemore operations than the abstract type, the additional operations cannotbe invoked.
The data structure used to locate operations is called an Abstract-Concretevector. Each variable has associated with it a vector with one entry foreach operation defined by its abstract type. The contents of the entryis the address of the corresponding procedure entry point in the concretetype. When an assignment is made, the vector may have to be changed ifthe new object is implemented by a different concrete type. The compilergenerates code to perform this change if it cannot tell the concrete typeof the object to be assigned. [BHJL86]
8. Inheritance and Delegation
Emerald supports type conformity (and hence object substitution), butit does not support (implementation) inheritance. Code cannot be explicitlyshared among object implementations (see the entry under 7. Types andClasses). The absence of code sharing is due to Emerald's use in distributedsystems; the mobility of an object is enhanced when it is self-contained,and hampered if it is dependent on other objects. Emerald allows differentimplementations to be used for the same abstract type within a single program.[RTLB+91]
9. Noteworthy Objects
As noted under 2. Objects, Emerald objects may be defined asbeing immutable.
See 9.6 other.
In Emerald, all objects are coded using the single object constructorconcept. At compile time, the Emerald compiler chooses among several implementationstyles for the object, picking one that is appropriate to the object'suse. Three different implementation styles are used:
1. Global objects can be moved within the network and can beinvoked by other objects not known at compile time (in other words, referencesto them can be exported). They are heap allocated by the Emerald kerneland are referenced indirectly. An invocation may require a remote procedurecall.
2. Local objects are local to another object (i.e., a referenceto them is never exported from that object). They are heap allocated bycompiled code. These objects never move independently of their enclosingobject. An invocation may be implemented by a local procedure call or byinline code.
3. Direct objects are local objects except that their data areais allocated directly in the representation of the enclosing object. Theseare used mainly for built-in types, and other simple objects whose organizationcan be deduced at compile time. [BHJL86]
10.2 Metaclasses/Metaobject Protocol
Each Emerald abstract type is an object, and can thus be manipulatedby the ordinary facilities of the language, such as assignment, constantbinding, and parameter passing. Type objects may be passed as parametersto implement polymorphism or inspected at run-time to implement run-timetype checking.
Any object that exports a getSignatureoperation that returns a Signatureis an abstract type. Objects of type Signatureare created by the type constructor syntax (typex ... end x). A Signatureis a built-in implementation of an AbstractTypethat can be generated only the compiler. A signature object exports a getSignatureoperation (returning itself) so it conforms to AbstractType.It also exports several secret operations that enable the Emerald implementationto determine the operations provided by the type, and the signatures ofthose operations. Because the names of these operations are secret, noprogrammer-defined objects will ever have types that conform to Signature;all signature objects must stem from a type constructor expression in someEmerald program. Consequently, the type checker is guaranteed to be ableto get adequate and consistent information about a type. [RTLB+91]
11. Object Languages
12. Semantics of Base Classes (+ type constructors)
13. Background and References
Emerald is not a particularly widely-used programming language. However,many concepts associated with Emerald, such as conformity, have had considerableinfluence in object-oriented language and system designs.
[BHJL86] A. Black, N. Hutchinson, E. Jul, and H. Levy, "ObjectStructure in the Emerald System", in N. Meyrowitz, ed., OOPSLA'86 Conference Proceedings, ACM, Sept., 1986, published as SIGPLANNotices, 21(11), Nov., 1986.
[BH90] A. Black and N. Hutchinson, "Typechecking Polymorphism inEmerald", Technical Report CRL 91/1, Cambridge Research Laboratory,Digital Equipment Corporation, 7 December 1990.
[Hoa74] C. A. R. Hoare, "Monitors: An Operating System StructuringConcept", Comm. ACM 17, 10 (October 1974), 549-57.
[RTLB+91] R. K. Raj, E. Tempero, H. M. Levy, A. P. Black, N. C. Hutchinson,and E. Jul, "Emerald: A General-Purpose Programming Language",Software--Practice and Experience 21(1), January 1991.
features matrixintro page