51
ReMoDeL: OOP Specification, 26 March 2010 ReMoDeL Object-Oriented Programming Model Anthony J H Simons Department of Computer Science University of Sheffield

ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010

ReMoDeL

Object-Oriented Programming Model

Anthony J H SimonsDepartment of Computer ScienceUniversity of Sheffield

Page 2: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 2

1. Introduction ....................................................................................................... 4

1.1 Goals of the ReMoDeL Project.................................................................... 4

1.2 Metamodelling Strategy and XML .............................................................. 4

1.3 Object-Oriented Programming .................................................................... 5

1.4 The OOP Metamodel Hierarchy .................................................................. 6

1.5 Common Semantic Model ........................................................................... 7

2. OOP Package Specification ..............................................................................10

2.1 Standard Conventions.................................................................................10

2.2 Package Element ........................................................................................11

2.3 Type Element .............................................................................................12

2.4 Basic Element ............................................................................................12

2.5 Interface Element .......................................................................................13

2.6 Class Element ............................................................................................14

2.7 Generic Element.........................................................................................15

2.8 Depend Element.........................................................................................16

2.9 Employ Element.........................................................................................17

2.10 Inherit Element .......................................................................................18

2.11 Satisfy Element.......................................................................................19

2.12 Member Element ....................................................................................20

2.13 Field Element .........................................................................................20

2.14 Method Element .....................................................................................22

2.15 Creator Element......................................................................................24

2.16 Variable Element ....................................................................................26

3. OOP Expression Language ............................................................................29

3.1 Expression Element....................................................................................29

Page 3: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 3

3.2 Identifier Element.......................................................................................30

3.3 Literal Element...........................................................................................30

3.4 Operator Element .......................................................................................31

3.5 Invoke Element ..........................................................................................33

3.6 Create Element...........................................................................................34

3.7 Sequence Element ......................................................................................36

3.8 Parallel Element .........................................................................................38

3.9 Select Element ...........................................................................................39

3.10 Iterate Element .......................................................................................41

3.11 Assert Element .......................................................................................44

3.12 Rescue Element ......................................................................................45

4. OOP System Construction ................................................................................47

4.1 The Main Program .....................................................................................47

4.2 Using Library Code....................................................................................49

4.3 Implementing Dynamic Object Management..............................................50

Page 4: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 4

1. Introduction

ReMoDeL, an acronym for Reusable Model Design Languages, is a research project undertaken at the University of Sheffield that aims to realise Model-Driven Engineering (MDE). This is a general strategy in software engineering that seeks to generate executable software systems directly from design models, rather than by writing programs in specific programming languages. ReMoDeL is inspired by, and shares some of the goals of, the Object Management Group’s specific initiative to develop a framework known as Model-Driven Architecture (MDA), but is not unduly constrained by any requirement to replicate all the richness and detail of OMG standard languages (UML, OCL, MOF). Instead, the aim of ReMoDeL is to realise a simpler proof-of-concept using minimalist techniques and to develop a reference implementation.

1.1 Goals of the ReMoDeL Project

The wider ReMoDeL project has certain longer-term goals in addition to those usually cited for MDA. It brings together a number of different “grand challenges” in software engineering.

Program-It-Yourself (PIY) is the idea that, in future, business end-users should be able to specify the kinds of systems that they need, using domain-specific languages tailored to express their requirements directly.

Scrap-Heap Challenge (SHC) is the idea that, in future, software will be cannibalised from existing systems, but not at the code-level, rather at the model-level, from which new systems will be automatically generated.

Self-Verification and Test (SVT) is the idea that, in future, design models will be automatically checked for consistency and completeness and generated code will be automatically tested against specifications.

From this it can be seen that ReMoDeL has a strong emphasis on regenerating robust software systems, directly from reusable models, in a timely fashion, to meet rapidly changing user requirements. This must be achieved while preserving the end-users’ investment in existing business data.

1.2 Metamodelling Strategy and XML

Central to the ReMoDeL strategy is the notion of different models and modelling languages, which must be able to represent software systems at different levels of abstraction. High-level models, close to user requirements specifications, are to be translated into low-level models, close to implementations. The transformations to apply are also described within the same modelling framework.

High-level models might include packages containing entity-relationship models and workflow diagrams or state machine diagrams. Low-level models might include database schemas and program code specifications. Transformations might include standardising and optimising a given model, or translating from one model into another, or generating program code in a particular programming language. There might be different codified transformation strategies that could be applied on different

Page 5: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 5

occasions, to yield a different kind of implementation, for example in a different programming language, or coupling a generated program to a distinct third-party database.

In order to provide a degree of uniformity in the way different modelling languages appear, the aim is to define all but the lowest-level implementation languages as dialects of the markup language XML, for which efficient processing tools already exist. The modelling concepts used within any particular language should also be defined within a class-based metamodel, expressing the commonalities and differences between the different modelling concepts. The metamodel may eventually be described within the same framework.

1.3 Object-Oriented Programming

This document describes the specification for the XML dialect used to define the core object-oriented programming model for ReMoDeL. The chief requirements for this language (henceforth known as OOP) are that it should be able to express common concepts in popular, strongly typed object-oriented programming languages (such as Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these languages.

This document therefore serves as a point of reference for two kinds of transformation activity in the wider ReMoDeL project:

for low-end code generators seeking to translate OOP into specific target languages, such as Java, C++, C# and Eiffel; and

for mid-level translators seeking to transform high-level design models into language-neutral OOP models.

The OOP Model language contains familiar concepts from object-oriented programming, such as Class, Interface, Field, Method and all the different kinds of Expression that make up the body of a method. The design of OOP is motivated by the desire to record the minimum information necessary that is still sufficient for generating code in a variety of popular object-oriented programming languages. To permit this, constructions in these languages were mapped back onto language-neutral structures, which preserve the same information. Certain idiomatic constructions present in individual languages, but not in others, have been excluded from the OOP Model, where these would have increased the overall complexity unduly.

Attention has also been paid to the semantics of execution in different target languages. To this end, a Common Semantic Model underpins the design of OOP, representing the degree of agreement, across all target programming languages, on their operational behaviour. The CSM is the “safe area”, within which it is possible to generate code in any of the target languages, and still obtain equivalent behaviour. There is also the Extended Semantic Model, which allows OOP constructions, which only translate into equivalent code in certain subsets of the target languages.

Page 6: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 6

1.4 The OOP Metamodel Hierarchy

Conceptually, the language constructions of OOP are organised in a hierarchy of model elements, which constitutes a metamodel for the language. The main generalisation relationships between elements are shown in figure 1. Other associations between elements are not illustrated.

Figure 1: Meta-model for the OOP language specification

Each of the terminal nodes in figure 1 corresponds to an XML element in the OOP language. The intermediate nodes group terminal nodes by similarity, according to the attributes they declare, or child elements that they dominate. For example, all elements under Property have the name and type attributes; all elements under Member also declare a visibility.

Element

Named

Classifier

Property Type

Basic

Class

Interface

Member

Field

Creator

MethodDepend

Employ

Inherit

Expression

Compound

Sequence

Parallel

Control

Select

Iterate

Identifier

Literal

Operator

InvokeVariable

Generic

Satisfy

Assert

Rescue

Create

Package

Page 7: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 7

The higher levels of this meta-model are generic to all ReMoDeL languages. Some of the intermediate nodes shown in figure 1 also play a part in other languages; for example, in the Data Base and Query (DBQ) language, a Role is also a kind of Property; likewise a Record is another kind of Type.

1.5 Common Semantic Model

The Common Semantic Model (CSM) defines an agreed operational semantics for OOP, which may be translated faithfully into all of the envisaged target languages. The Extended Semantic Model (ESM) supports features that may only be translated into specific target languages.

1.5.1 Reference semantics of objects

All objects have reference semantics and are freely created and destroyed dynamically during program execution. While dynamic allocation is standard in Java and C#, the default in Eiffel and similar languages, to achieve this in C++ requires a particular translation model to manage dynamically created objects. The suggested strategy is smart pointers, to be provided in an included software library. Garbage collection is assumed; and is built into some target languages, but may be provided through reference counting in other languages without automatic memory management.

While OOP distinguishes Basic from Class types, this has more to do with the atomicity of Basic types, than with any intended distinction between value- and reference-types. Instances of Basic types may also be treated like immutable objects and freely substituted where general objects are expected. Translation between raw value types and boxed-up object types should be handled either by the target language directly (such as Java, C#), or through special code generation strategies.

1.5.2 Single- and multiple-inheritance

Different target languages have different policies on single- or multiple-inheritance. The CSM defines an agreed area of overlap, which may be translated into all the envisaged target languages. In the CSM, a class may have at most one concrete superclass, but may satisfy multiple abstract interfaces. This translates directly in Java and Objective C; however in Eiffel and C++, which support multiple-inheritance but have no interface types, interfaces may be treated as fully abstract classes (e.g. in Eiffel’s marriage of convenience paradigm).

In the Extended Semantic Model, it is possible to construct models with multiple-inheritance in OOP, so long as the target languages are restricted to those supporting multiple-inheritance (such as C++ and Eiffel). In this case, a class should inherit the (distributed) union of the features of its parents. It should merge identical inherited declarations automatically, but force the designer to select how to combine non-identical inherited features by explicit method combination.

The semantics of inheritance is essentially identical for relationships between concrete classes, abstract classes and (abstract) interfaces. However, the term inherit is always used in OOP where the supertype is a Class, and the term satisfy is always used, where the supertype is an Interface. This facilitates enforcing the allowable numbers of supertypes, in each target language.

Page 8: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 8

1.5.3 Overloading and dynamic binding

To avoid ruling out target languages that do not support overloading (such as Eiffel), each Member feature in OOP (viz. Field, Method, and Creator) should be defined with a unique name within the namespace defined by a class (including its eventual subclasses). This means that no further resolution need be performed on the types of argument lists when looking up members. Furthermore, it then becomes much easier to determine automatically when methods are being redefined and dynamic binding is required.

The only time a duplicate Member name should appear is when a method is being overridden in a subclass by a redefined version. Translators will then be able to determine the need for static or dynamic binding, by global analysis of the hierarchy (allowing optimisations with Java final, or C++ virtual declarations).

1.5.4 Object construction

Similarly, creation procedures (Creators) are named uniquely in OOP, as though they were methods initialising an instance of the created type with field values. Object creation is handled in a variety of ways in the different target languages, which the OOP syntax tries to support in its neutral approach. The Creator names translate into creation procedures in Eiffel, init-methods in Delphi/Object Pascal, and factory methods in Objective C. The Creator types translate into global constructors in Java, C++ and C#.

Since creation procedures are identified explicitly in OOP, translators are free to choose the most efficient method to construct member fields (assignment in Java, but cheaper initialisation in C++). Similarly, the way in which values are passed back to superclass constructors can be treated like renaming in Eiffel, super-invocation in Java and superclass constructor calls in C++. In the ESM, multiple super-initialisations are supported by explicitly naming each super-object explicitly in the Inherit directive, so that all super-invocations may be suitably resolved.

The act of creation is distinct (using Create) from the act of method invocation (using Invoke) in OOP. This allows translators to determine locally whether special targetlanguage syntax for object construction is appropriate.

1.5.5 Visibility and access permissions

The CSM Supports private, protected and public access to members, which translate smoothly into visibility declarations in all target languages. The ESM supports package visibility, which translates directly into Java, but commutes to protectedvisibility in other languages. Translators may then need to provide specific access permissions to classes or methods, via selective export mechanisms (Eiffel) or friend-declarations (C++).

1.5.6 Instance- versus class-methods and fields

The CSM supports the notion of fields shared by all instances of a class, but not methods that can be invoked only against class-objects. The notion of static fields and methods is semantically obtuse (when applied to fields and methods, static means

Page 9: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 9

different things: a static field is shared by all instances, and allocated to the class-object, rather than to every instance; but methods are already shared by the class, and static indicates that the method may only be invoked on the class-object, whereas static fields are also accessible in instances).

The ESM may in future seek to accommodate a distinction between instance-level behaviour and class-level behaviour, if OOP is eventually extended to provide a full reflective metamodelling capability.

1.5.7 Assertions and exception handling

The CSM defines a minimal common approach to specifying semantic correctness and handling exceptions. Target languages as diverse as Eiffel and Java have quite different approaches, for example in Eiffel, exceptions are integer-valued signals passed to a single kind of handler; whereas in Java, exceptions are first-class objects, which are bound to different handlers using the polymorphic type system. The only common notion is the idea of unwinding the stack at the point of failure.

All kinds of semantic assertion are enforced using the Assert statement. In the CSM, assertions are added to a Class (as a data type invariant), or to a Method or Creator(as preconditions), or to a Sequence of statements in the body (as postconditions). Violating a precondition raises an exception in the caller; violating an invariant or postcondition raises an exception in the current operation. This is native in Eiffel, but requires explicit try-catch blocks in any Java, C++ or C# translation.

In the ESM, assertions may also be added to an Interface. Languages which translate interfaces into fully abstract classes are able to encode pre- and postconditions and invariants into secret methods.

The CSM assumes a single Rescue exception handler (for the sake of Eiffel) and is limited to a single kind of runtime exception class (in Java and C++) for broken assertions. The default behaviour is that handlers clean up the local state and pass the failure up the stack. Resumption must be specified explicitly, by stating the number of times the operation may be attempted, up to a maximum number of attempts, during which the operation must either succeed, or eventually fail.

Page 10: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 10

2. OOP Package Specification

The following describes the high-level organisation of model elements within a Package, the root element in the ReMoDeL OOP model. The order of presentation broadly follows the hierarchical structure of the XML syntax for OOP. Subsections introduce each model element separately and list the attributes and their values that may be defined. Unless attributes are marked optional, they are understood to be mandatory.

2.1 Standard Conventions

A number of conventions are observed in the OOP XML syntax.

2.1.1 Typographical conventions

By convention, all XML element names are written in “CapitalCase”, a style inspired by Java type identifiers, in which identifiers are capitalised at all word boundaries. Single-word identifiers are simply capitalised, whereas multi-word identifiers are created by concatenation of several capitalised words.

By convention, all XML attribute names are written in “camelCase”, a style inspired by Java variable and member identifiers, in which identifiers are capitalised only at internal word boundaries. Single-word identifiers are simply in lower case, whereas multi-word identifiers are created by concatenation of an initial lower case word with further capitalised words.

By convention, all enumerated constant values are also written in “camelCase”. This allows language keywords such as “private” and “public” to appear in the same style as they would in generated code, and is consistent with the usual lower case style for other program constants, such as “false” and “true”.

2.1.2 XML header and single root

Like all valid XML documents, an OOP file must begin with a valid XML header and the document must contain a single root element. In all the ReMoDeL languages, the root element is always a Package, a logical namespace, used to package different kinds elements according to the model type.

<?xml version=”1.0” encoding=”UTF-8” ?><Package name=”Core”> <!-- other element data inserted here --></Package>

The UTF-8 character encoding is the most common one used, although it is possible to use other encodings. This and the XML version number may be needed by specific XML processing software (such as DOM, SAX, JDOM), but otherwise play no part in the ReMoDeL specification.

Page 11: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 11

2.2 Package Element

In OOP, the Package element serves firstly to define a namespace within which the contained elements are defined; and secondly to declare a directory structure within which code may be generated.

2.2.1 Package attributes

A Package element defines the following attributes:

name – the unique name of the package;

model – the model type, here “OOP” (optional);

location – a relative directory structure (optional).

The following is an example:

<Package name=”Finance” model=”OOP” location=”example.finance”>

<!-- other element data inserted here --></Package>

A package name is conventionally written in capital case. The name is unique to the logical Package, such that if multiple XML files were loaded, containing root Packages having the same name, the contained elements should be merged in a single logical Package. The name may be translated into a namespace in languages like C++.

The model type is optional, but may be useful where tools wish to check that the opened XML file is of the right kind, before the anticipated processing is carried out. Here, the “OOP” model type indicates that this Package describes an OOP model, rather than any other kind of model.

The location is an abstract pathname, expressed in an operating system neutral way using the “dot” as a path separator (similar to Java). This denotes a relative directory structure, under the current working directory, into which generated code artefacts might be placed. The location may also be translated into a hierarchical package name in languages like Java.

The location is frequently needed in OOP, whereas it may be optional in other kinds of model. If not supplied, then the location of generated code artefacts is assumed to be the current working directory.

2.2.2 Package contents

The contents of an OOP Package include zero-or-many occurrences of each of the following elements. These are not ordered, but typically appear in the following order:

Basic – the declaration of a primitive, or enumerated data type;

Page 12: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 12

Interface – the declaration of an object-oriented interface type.

Class – the declaration of an object-oriented class type;

See below for the specification of these elements.

2.3 Type Element

All types in OOP are considered some kind of Type. While this is an abstract element in the metamodel (viz. no XML element tags called Type appear), it serves to declare some common properties shared by all type elements, which include: Basic, Generic, Class and Interface types.

2.3.1 Type attributes

Most Type elements (viz. Basic, Class and Interface types) declare the attributes:

name – the name of the type, unique within any collection of packages imported into a single model;

visible – if private, indicates a restriction on the export visibility of a type, within its owning package (optional).

initial – the default initial value for variables of this type, which is null if not otherwise specified (optional).

The name of any kind of type is written in CapitalCase, following standard OOP conventions for type names.

The visible attribute can be used to restrict the availability of a type to the current package, if private is indicated. By default, all package elements are public, meaning that they are available for import by other packages.

The initial value for a type declares the default initial value to use when declaring variables of this type. Initial values are written as strings, which are interpreted as literal values (see the Literal element). By default, all types have the initial value null, unless otherwise specified.

2.4 Basic Element

The Basic element serves to declare standard names for the primitive types provided in object-oriented languages. These are translated in language-specific ways, and certain target languages may support more or fewer Basic types. Basic also declares enumerated types in OOP.

There is no distinction made in OOP between the raw “value” and boxed-up “object” representations of a Basic type. Where a target language must distinguish these, the code generation process must handle this. A number of target languages already deal with boxing and un-boxing automatically.

Page 13: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 13

2.4.1 Basic attributes

A Basic type declares the following attributes:

name – the canonical name of the primitive type;

visible – any export visibility restriction (optional);

initial – the default initial value for variables of this type.

Some examples include:

<Basic name=”Integer” initial=”0” /><Basic name=”Decimal” initial=”0.0” /><Basic name=”Void” />

OOP uses standard names for all Basic types, rather than language-specific names such as int, double, Integer, Real, int32, float etc. Basic type names are written in capital case, like all type names in OOP. The translation of any given OOP Basictype into a target language type is determined by the translation rules applied at code generation time. The initial attribute is mandatory for a Basic type, to specify the default initial value for variables of this type.

2.4.2 Basic contents

A Basic type declaration may be used to define a symbolic or enumerated type, in which case its contents are the symbolic names used for each of the enumerated values. These are declared as Literal values (see section 3 below). For example:

<Basic name=”Boolean” initial=”false”> <Literal value=”false” type=”Boolean /> <Literal value=”true” type=”Boolean /></Basic>

2.5 Interface Element

The Interface element serves to declare an object-oriented interface type, containing abstract method signatures. An Interface may be translated directly in languages that support interfaces (e.g. Java, Objective C), and may be translated into a fully abstract class in languages with multiple inheritance (e.g. C++, Eiffel). Signatures may translate into pure virtual functions (in C++) or deferred methods (in Eiffel).

2.5.1 Interface attributes

An Interface element declares the following attributes:

name – the unique name of the interface type;

visible – any export visibility restriction (optional);

An example is given by:

Page 14: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 14

<Interface name=”Comparable”> <!-- other element data inserted here --></Interface>

Translators will automatically ensure that interfaces are declared abstract, or deferredwhere this is required by the target language syntax.

2.5.2 Interface contents

The contents of an Interface include zero or more occurrences of each of the following elements (but at least one Method signature). These are expected to occur in the given order:

Generic – a declaration of a formal generic parameter (optional);

Employ – a directive to use another type (optional);

Satisfy – a directive to extend a super-interface (optional);

Method – the declaration of a method signature;

Assert – the declaration of a data type invariant (optional, illegal in CSM).

An Interface must employ any component type (Basic, Class or Interface) on which its signatures depend. An Interface may satisfy (and so extends) another interface. See below for specifications of these elements.

The main contents of an interface are one or more Method signatures. These must all be marked abstract and have no method body (see definition of Method below).

In the ESM only, an Interface may also contain one or more Assert statements, declaring a data type invariant (see definition of Assert below).

2.6 Class Element

The Class element serves to declare an object-oriented class type, containing field and method declarations. An OOP Class may satisfy multiple interfaces and inherit from at most one super-class in the Common Semantic Model, but may inherit from multiple super-classes in the Extended Semantic Model (targeting specific languages that support this).

2.6.1 Class attributes

A Class element declares the following attributes:

name – the unique name of the class type;

visible – any export visibility restriction (optional);

library – indicates whether this class is predefined (optional).

The following illustrates several examples:

Page 15: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 15

<Class name=”CurrentAccount”> <!-- other element data inserted here --></Class>

<Class name=”InterestRates” visible=”private”> <!-- other element data inserted here --></Class>

<Class name=”String” library=”true”> <!-- other element data inserted here --></Class>

The optional library attribute, when “true”, indicates that a Class is predefined in a standard library, meaning that translators need not generate any code for the class. The contents of a library Class element are restricted to elements denoting signatures, to support the checking of constructor or method invocations. In this respect, a library Class provides a checked interface for predefined code.

Otherwise, if the contents of a Class element include at least one element denoting asignature with no implementation, translators may need to declare such a class as abstract or deferred, according to the syntax of the target language.

2.6.2 Class contents

The contents of a Class include zero or more occurrences of each of the following elements (with at least one Field or Method declaration). These are expected to occur in the given order:

Generic – a declaration of a formal generic parameter (optional);

Inherit – a directive to inherit from a superclass (optional);

Satisfy – a directive to satisfy an interface (optional);

Employ – a directive to use another type (optional);

Field – the declaration of a field member (optional);

Method – the declaration of a method member (optional);

Creator – the declaration of a constructor member (optional);

Assert – the declaration of a data type invariant (optional).

See below for the specification of these elements. Some were described briefly above, when introducing the Interface element.

2.7 Generic Element

The Generic element serves to declare a formal generic parameter. Generic is different from other Type elements, in that it stands for possibly many different types, which might instantiate the parameter.

Page 16: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 16

2.7.1 Generic attributes

The Generic element declares (only) the following attributes:

name – the formal name of the generic parameter;

restrict – the name of an upper bound class or interface (optional).

The name may be used like a type name in the other declarations within a Classelement, to type fields or methods. A class or interface containing Generic elements is a generic class, parameterised over one or more of its internal types. For example, the following declares a generic List class, with a generic parameter called Item, standing for the list element type:

<Class name=”List”> <Generic name=”Item” /> <!-- other class contents inserted here --></Class>

Generic types are substituted by actual types when the generic class is used to type some variable or field. In this case, the actual types appear as part of the class name, enclosed in square brackets. The following is a variable declaration for a list of Integer objects, which replaces Item by Integer:

<Variable name=”intList” type=”List[Integer]” />

The restrict attribute may be used to restrict the generic parameter to range over types that satisfy the named class or interface, which is the upper bound. For example, the following Map class declares two generic parameters, called Key and Value, where the Key must satisfy the Hashable interface:

<Class name=”Map”> <Generic name=”Key” restrict=”Hashable” /> <Generic name=”Value” /> <!-- other class contents inserted here --></Class>

This is translated into a constrained generic parameter in Eiffel or Java. There is no equivalent of constrained generic parameters in C++. Generic classes with more than one generic parameter are used in much the same way, using a comma to separate the actual types supplied. The following variable declaration replaces Key by String(which satisfies Hashable) and Value by Person:

<Variable name=”friends” type=”Map[String, Person]” />

Translators must be able to analyse type names which contain “[ ]” square brackets and separate out the actual types. The actual types may need to be imported, if they are not in the current package (see the definition of Employ, below).

2.8 Depend Element

All type dependencies in OOP are expressed using some kind of Depend element. While this is an abstract element in OOP (viz. there is no XML element tag with the

Page 17: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 17

name Depend), it serves to declare some common properties shared by all dependencies, namely: Employ, Inherit and Satisfy dependencies.

2.8.1 Depend attributes

A Depend element (one of Employ, Inherit or Satisfy) defines the following attributes:

type – the name of the type on which the current definition depends;

from – the name of the other package owning the type (optional);

location – the relative pathname from which to obtain it (optional);

The type may refer to any Basic, Class or Interface type, which is needed as part of the current definition.

The from attribute refers to the package name from which the type is imported; and is only needed if the type comes from a different package. This may correspond to a namespace in languages like C++, where it is necessary to qualify elements by the namespaces in which they are defined.

The location is an abstract pathname, expressed in an operating system neutral way using the “dot” as a path separator (similar to Java). This denotes a relative directory structure, under the current working directory, within which generated code artefacts might be located. The location may be translated directly into a hierarchical package name qualifier in languages like Java. In languages like C++, the translation will have to process pathnames to obtain the relative locations of included header files.

2.9 Employ Element

The Employ element serves to declare a composition dependency. It declares acomponent type, on which the current type definition depends. For example a class may declare a field of this type, or an interface may declare a method signature using this type, or a generic declaration may be constrained by this type, in which case an Employ dependency must be supplied.

2.9.1 Employ attributes

The Employ element declares the following attributes:

type – the name of the type on which the current definition depends;

basic – true, if the employed type is a basic or enumerated type;

from – the name of the other package owning the type (optional);

location – the relative pathname from which to obtain it (optional);

The basic attribute must be set to true, if the employed type is a primitive type, or an enumerated type. This is used by C++ translators to decide whether to include the header file for the type, or forward-declare the type.

Page 18: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 18

The following example shows how an Account defined in the Finance package may employ a Person from a different People package (e.g. because Account defines an account holder field, of the type Person):

<Package name=”Finance” model=”OOP” location=”example.finance”>

<Class name=”Account”> <Employ type=”Person” from=”People”

location=”example.people” /> <!-- other class data inserted here --> </Class></Package>

The from attribute refers to the name of the package from which the type is imported. This may translate into a using directive in languages like C++, to disambiguate from which namespace the type is being imported.

The location attribute refers to the eventual directory location of the generated code for the imported type. If no location is provided, this defaults to the same location as for the current Package. Some languages like C++ still require include directives for code artefacts loaded from the current package (unlike Java).

2.10 Inherit Element

The Inherit element serves to model inheritance in OOP, whereby a subclass obtains some of its fields or methods implicitly from its parent superclass. A class may declare one (CSM) or many (ESM) parent classes; in the latter case it inherits the union of its parents’ features. The inherited type is always a Class element.

2.10.1 Inherit attributes

The Inherit element declares the following attributes:

type – the name of the class from which the current type inherits;

from – the name of the other package owning the class (optional);

location – the relative pathname from which to obtain it (optional);

name – the name of the super-object (optional, required in ESM).

The type attribute declares a superclass from which the current class inherits. The from and location attributes are only necessary if the superclass comes from a different package, in which case they are used as above.

The name attribute is used to name the super-object, for the purposes of super-method or super-constructor invocation. If this is not supplied, the name super is implicitly assumed by default. For example, the following two declarations are equivalent:

<Class name=”Lecturer”> <Inherit type=”Person” /> <!-- other class data inserted here --></Class>

Page 19: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 19

<Class name=”Lecturer”> <Inherit name=”super” type=”Person” /> <!-- other class data inserted here --></Class>

Naming the super-object is optional for single inheritance (CSM), but compulsory for multiple inheritance (ESM), where it is necessary to distinguish which parent’s method (or constructor) is to be invoked. The following example illustrates this:

<Class name=”TeachingAssistant”> <Inherit name=”pupil” type=”Student” /> <Inherit name=”teacher” type=”Lecturer” /> <Method name=”equals” type=”Boolean” visible=”public”> <Variable name=”other” type=”TeachingAssistant” /> <Operator symbol=”return”> <Operator symbol=”and”> <Invoke name=”equals”> <Identifier name=”pupil” scope=”special” /> <Identifier name=”other” /> </Invoke> <Invoke name=”equals”> <Identifier name=”teacher” scope=”special” /> <Identifier name=”other” /> </Invoke> </Operator> </Operator> </Method> <!-- other class data inserted here --></Class>

Here, method combination is required, to define a new version of equals() that depends on inherited methods from both parent classes. The body of the new equals()method refers to pupil.equals() and teacher.equals() unambiguously. Here, the results of the super-methods are combined using logical and, but in general any kind of wrapping code might be used.

2.11 Satisfy Element

The Satisfy element serves to model interface satisfaction in OOP, the ability of a typeto conform to an interface. The current class or interface is understood to provide at least the methods of the associated interface. This concept is more general than interface implementation (in Java), since it also subsumes the notion of extending a super-interface. The satisfied type is always an Interface.

2.11.1 Satisfy attributes

The Satisfy element declares the following attributes:

type – the name of the interface which the current type satisfies;

from – the name of the other package owning the interface (optional);

location – the relative pathname from which to obtain it (optional);

Page 20: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 20

These are used in the same way as above. The following example illustrates an Author class from the People package that satisfies the Hashable interface , which is obtained from the Core package:

<Package name=”People” model=”OOP”location=”example.people”>

<Class name=”Author”> <Satisfy type=”Hashable” from=”Core”

location=”lib.core” /> <!-- other class data inserted here --> </Class></Package>

The Satisfy element exists to support target languages which distinguish concrete inheritance from interface satisfaction. The from and location attributes used here need only be supplied if the satisfied type comes from a different package.

2.12 Member Element

The Member element is abstract in OOP, but serves to define properties that are common to all elements that are structural members of a class or interface. These include: Field, Method and Creator elements, which have common properties.

2.12.1 Member attributes

Member elements define the following attributes:

name – the unique name of the member in the hierarchy;

type – the type of the member (the field, or result type);

visible – the internal or external visibility of the member (optional);

The name of a member is given by convention in camelCase. It should refer uniquely to a given member within the type hierarchy, that is, by convention OOP avoids name overloading as a deliberate policy. The only time a duplicate name appears is where a member is being redefined in a subclass.

The type of a member is any Basic, Class or Interface type. The type must refer to an element that was either defined within the current package, or that was imported from a different package via one of the Depend directives.

The optional visible attribute may take on any of the enumerated values private, protected or public in the CSM. If not supplied, the default interpretation in OOP is that the member is private. The ESM offers package visibility, which translates smoothly in Java, but requires a work-around in C++ (using friend declarations) and in Eiffel (using selective exports).

2.13 Field Element

The Field element serves to declare a field member, or attribute of a class. This denotes some data value contained by the class, or some reference to another type

Page 21: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 21

known to the class. Fields take on unique values in each instance, unless they are shared fields, in which case their value is shared by all instances of the class.

2.13.1 Field attributes

A Field element declares several attributes:

name – the unique name of the field in the hierarchy;

type – the type of the field;

visible – the internal or external visibility of the field (optional);

shared – whether the field is shared by the class (optional);

value – the initial value to assign to the field (optional);

The following typical field definitions have sensibly restricted visibility:

<Field name=”forename” type=”String” visible=”private” /><Field name=”age” type=”Natural” visible=”protected” />

where private means visible only within the owning class, and protected means visible also in all subclasses inheriting from the defining class.

The optional shared attribute, when set to “true”, declares that a field is shared, meaning that it is owned by the class, rather than by instances of the class. (In Java and C++, this is called a static field. In Eiffel, this would be a once function). If not supplied, fields are understood to be replicated, unique in each instance.

The optional value attribute declares a literal value to initialise the field at declaration time, replacing the default value for the type (see section 2.3). If the initial value must be computed, the Field element may contain an expression-element to initialise it. Translators may use initial field values to generate a default constructor for the class.

2.13.2 Field contents

If a Field is initialised using a computed expression, this is supplied as the content of the Field element (see section 3 for the full expression syntax). Shared fields must always be initialised this way, since they cannot use an object constructor:

<Field name=”netRate” type=”Natural” shared=”true”> <Operator symbol=”minus”> <Identifier name=”grossRate” scope=”object” /> <Identifier name=”taxRate” scope=”object” /> </Operator></Field>

A special case is where a Field is initialised using the object constructor for the same type. This requires a constructor invocation, with the field as the implicit target (see section 3 for a definition of the Create and Literal elements):

Page 22: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 22

<Field name=”owner” type=”Person” shared=”true”> <Create name=”make” type=”Person” implicit=”true”> <Literal value=”John” type=”String” /> <Literal value=”Smith” type=”String” /> <Literal value=”25” type=”Integer” /> </Create></Field>

A similar style of declaration with initialisation is available for local variables (see the definition of Variable, below).

2.14 Method Element

The Method element serves to declare a method, or member function of a class. A method is uniquely named within the scope of its owning class (see the discussion of the Common Semantic Model, above).

2.14.1 Method attributes

The Method element declares the following attributes:

name – the unique name of the method in the hierarchy;

type – the result type of the method;

visible – the internal or external visibility of the method (optional);

override – true, if the method replaces an earlier version (optional).

A method is typically granted public visibility, but may be protected (if a shared sub-algorithm) or private (if an implementation secret). For example, the following publicmethod returns the value of the age field:

<Method name=”getAge” type=”Integer” visible=”public”> <Sequence> <Operator symbol=”return”> <Identifier name=”age” scope=”object” /> </Operator> </Sequence></Method>

If the method body Sequence is omitted, the Method is understood to be abstract, denoting a signature, rather than an implementation. Abstract signatures are typically found as the contents of an Interface, but may also occur in an abstract Class (or library Class – see above).

<Method name=”area” type=”Decimal” visible=”public” />

The above example is an abstract signature, the pattern for a method to compute the area of geometric shapes. In this example, the Method has no further contents. Abstract methods may also declare Variable parameters (see below), denoting their formal arguments, as part of their contents.

Page 23: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 23

Subclasses may freely implement a previously-declared abstract method, simply by supplying a Sequence body. However, if the intention is to redefine or override an existing method implementation, the override attribute must be set to true. This is exploited by translators for languages like Eiffel, where redefinition must be flagged explicitly.

2.14.2 Method contents

The contents of a Method element include the following elements, which are expected to occur in the order given:

Variable – the declaration of one or more formal parameters (optional);

Assert – the declaration of one or more preconditions (optional);

Sequence – the body of the method (optional, if abstract).

If one or more Variable elements appear, these denote the formal arguments to the method. If no Variable elements appear, the method has no arguments. See below for a definition of the Variable element.

If one or more Assert elements appear in the immediate scope of a Method, these denote preconditions to the method. If the preconditions are not satisfied, this will cause an exception to be raised in the caller (see section 3 below). Assert elements may be added only to concrete methods in the CSM. This is because certain target languages cannot implement assertions added to interfaces. The ESM may support adding assertions to abstract signatures (and interfaces).

The body of a Method element contains at most one Sequence element, denoting the statements to execute when the method is invoked. This sequence may contain arbitrary statements and perform arbitrary computation (see section 3).

The following example shows a typical update method, with one formal parameter and a body expression, a sequence containing one sub-expression to assign the parameter’s value to the corresponding object field (see section 3):

<Method name=”setAge” type=”Void” visible=”public”> <Variable name=”age” type=”Natural” /> <Sequence> <Operator symbol=”assign”> <Identifier name=”age” scope=”object” /> <Identifier name=”age” scope=”local” /> </Operator> </Sequence></Method>

Any Method that has previously been defined may later be invoked using the Invokeexpression-element (see section 3 below).

Page 24: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 24

2.15 Creator Element

The Creator element serves to define a constructor for the owning class. This has a similar syntax to the Method element. Each Creator is a uniquely named constructor, with a name like “make” (c.f. initialisation functions in Eiffel or Delphi), and must also have a unique type signature within its owning class (for the sake of translations into Java and C++). A Creator is understood to create and initialise a valid object in the target variable on which it is invoked.

2.15.1 Creator attributes

The Creator element declares the following attributes:

name – the unique name of the constructor in the hierarchy;

type – the class type of the object being constructed;

visible – the internal or external visibility of the constructor (optional);

A creator is typically granted public visibility, but may be protected (if a shared algorithm). For example, the following public creator called make creates and initialises an instance of Annual, a class which declares a single age field:

<Creator name=”make” type=”Annual” visible=”public”> <Variable name=”age” type=”Natural” /> <Sequence> <Operator symbol=”assign”> <Identifier name=”age” scope=”object” /> <Identifier name=”age” /> </Operator>

</Sequence></Creator>

The creator assigns the value of the age parameter to the field, also called age. There is no name-clash in OOP because of the explicit object scope given to the field identifier. Translators for specific target languages will have their own conventions for disambiguating field and local variable names.

A complete set of Creators must be defined for each new class (for the sake of Java, C++) and are not implicitly inherited (as in Eiffel, Delphi). Since Creators are always redefined, technically they always replace earlier versions, so it is redundant to have to specify an override attribute. Also, Creators are treated specially, in that subclass versions may have longer argument signatures than superclass versions.

The Java or C++ translation of the above Creator will produce a constructor with the signature: Annual(unsigned). The Eiffel translation will produce a named feature in the creation list called: makeAnnual(NATURAL_32), to distinguish it from other constructors that build super- or subclasses.

Page 25: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 25

2.15.2 Creator contents

The contents of a Creator element include the following elements, which are expected to occur in the order given, similar to Method:

Variable – the declaration of one or more formal parameters (optional);

Assert – the declaration of one or more preconditions (optional);

Sequence – the mandatory body of the constructor.

The Variable elements denote formal construction parameters. The Assert elements denote preconditions to construction, which raise an exception in the caller if they are violated, in a similar way to Method above.

The body of a Creator element contains exactly one Sequence element, denoting the statements to execute to initialise the object. The sequence may contain super-construction and local assignments (see section 3 for the full expression syntax). A complete example of a Creator is given below, illustrating both super-construction and local initialisation:

<Creator name=”make” type=”Person” visible=”public”> <Variable name=”forename” type=”String” /> <Variable name=”surname” type=”String” /> <Variable name=”age” type=”Integer” /> <Sequence> <Create name=”make” type=”Annual”> <Identifier name=”super” scope=”special” /> <Identifier name=”age” /> </Create> <Operator symbol=”assign”> <Identifier name=”forename” scope=”object” /> <Identifier name=”forename” /> </Operator> <Operator symbol=”assign”> <Identifier name=”surname” scope=”object” /> <Identifier name=”surname” /> </Operator> </Sequence></Creator>

Here, it is assumed that Person inherits from the Annual superclass defined above, which declares the age field. The body Sequence of the Creator consists of a super-invocation of the creator make to initialise the super-object with the supplied ageargument, followed by assignment statements to initialise the remaining fields of a Person object from the remaining arguments.

Translators are expected to convert this super-construction and assignment syntax appropriately, for example, in C++ it is usual to perform cheaper initialisation, rather than more expensive assignment (which is a distinct operation) and to construct the super-object by calling the super-type’s global constructor by name. Since ReMoDeL OOP supports both default Field values and construction arguments, the strategy recommended for C++ translators is to use initialisation for super-construction and

Page 26: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 26

for default Field values, but use assignment for regular construction arguments. This preserves the semantics of default values (which may be replaced by explicit construction arguments).

Any Creator that has been previously defined may later be invoked using the Createexpression-element (see section 3 below). In this way, OOP distinguishes object construction from method invocation, since these kinds of operation are sometimes treated quite differently in target languages. In particular, if a class has generic parameters, actual types must be supplied at construction-time.

2.16 Variable Element

The Variable element serves to declare the formal parameters for methods and creators; to declare local variables at the head of any Sequence element; and to declare iteration variables at the start of any Iterate element. A Variable may optionally be initialised to the value of an arbitrary expression, at declaration.

2.16.1 Variable attributes

Variable elements define the following attributes:

name – the name of the variable, a locally scoped identifier;

type – the type of the variable, a basic, class or interface type;

value – the literal value to assign to the variable (optional);

limit – the upper or lower limit on the variable’s range (optional);

range – one of rising, falling or foreach (optional).

The following is an example of usage as a formal parameter, in which the setAgemethod has a single parameter age, of the type Integer:

<Method name=”setAge” type=”Void” visible=”public”> <Variable name=”age” type=”Integer” /> <!-- other method data inserted here --></Method>

The following is an example of usage as a local variable, scoped within a sequence, and whose initial value is set to 0.0 using the value attribute:

<Sequence> <Variable name=”total” type=”Decimal” value=”0.0” /> <!-- other sequence data inserted here --></Sequence>

The name attribute declares the locally-scoped name of the variable. The usual rules of nested scope apply; that is, a variable in the outermost scope (a method or constructor parameter) may be temporarily hidden by introducing an identically named variable in an inner scope (inside a Sequence block). Variable names may be shared with Field names without confusion, since these are resolved separately.

Page 27: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 27

The type of a variable is any Basic, Class, Interface or Generic type. The type must refer to an element that was either defined within the current package, or that was imported from a different package via one of the Depend directives.

The optional value attribute declares a literal value to initialise the variable at declaration time. If supplied, this replaces the default initial value for that type (see section 2.3). Alternatively, if the initial value must be computed, the Variable may contain an expression-element to initialise it (see below). In this case, no literal initial value should also be declared.

The range attribute need only be supplied if the Variable is being used as a loop variable in an iteration. It specifies what kind of iteration behaviour is expected. In this case, both the value and limit may be supplied, representing the initial value and backstop limit of the iteration. See the definition of Iterate below.

The limit attribute is only relevant in the context of a counted iteration, in which a numerical variable may increase, or decrease, up to a limit. The limit is a backstop value, excluded from the range of the iteration. See the definition of Iterate below.

2.16.2 Variable contents

The contents of a Variable element may include:

an initial value expression (optional);

an upper or lower limit expression (optional).

A Variable element may contain a single sub-expression denoting a computable initial value for the variable, when it is declared. A simple example is:

<Variable name=”total” type=”Natural”> <Operator symbol=”plus”> <Identifier name=”basic” /> <Identifier name=”extra” /> </Operator></Variable>

This initialises the new variable total with the sum of the values found in the existing basic and extra variables. This style should be used to initialise a variable, where the initial value must be computed and cannot be declared as a literal.

If the variable has a class-type, the implicit object creation syntax may be used to construct and initialise an instance of the same class, at the time of declaration:

<Variable name=”visitor” type=”Person”> <Create name=”make” type=”Person” implicit=”true”> <Literal value=”John” type=”String” /> <Literal value=”Smith” type=”String” /> <Literal value=”25” type=”Integer” /> </Create></Variable>

Page 28: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 28

The make constructor creates a Person instance in the variable named visitor. The attribute implicit must be set to true in the Invoke element, to indicate that the enclosing variable visitor is in fact the implicit target of the constructor invocation.

Variables may be initialised in this way at declaration time with an object of the same type. To initialise with an object of some subclass type, the Create-expression must name the more specific type explicitly:

<Variable name=”visitor” type=”Person”> <Create name=”register” type=”Student” implicit=”true”> <Literal value=”John” type=”String” /> <Literal value=”Smith” type=”String” /> <Literal value=”25” type=”Integer” /> <Literal value=”6396642909” type=”Integer” /> </Create></Variable>

The local variable visitor is declared and initialised to a Student instance (using a Creator in the class Student, called register); dynamically, visitor will contain a Student object, even though it was declared of the type Person.

When a Variable is used in a counted iteration, it may contain both an initial value expression and an upper (or lower) limit expression, the backstop to the iteration. These have the same purpose as described for the value and limit attributes, in the context of iteration. See the definition of Iterate below.

Page 29: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 29

3. OOP Expression Language

The following describes the low-level organisation of model elements that denote executable expressions in OOP. These are the body statements of the constructors and methods of classes.

3.1 Expression Element

All computable expressions are considered to be some kind of Expression in the OOP meta-model. This element is abstract (viz. it never appears as an XML tag in OOP), but most constructions in the execution language have one or more operands, whose type is given as Expression, the most general type. Actual terms will be of some subclass of Expression: examples include the atomic expressions, such as Identifierand Literal; the simple expressions, such as Operator and Invoke; the compound expressions, such as Sequence and Parallel; and the control expressions, such as Select and Iterate.

3.1.1 Expression attributes

All expressions may have an optional attribute:

restrict – a type restriction on the expression, which may correspond to a type downcast (optional).

The restrict attribute, if present, is given the value of some class-type (possibly with generic parameters). This may be interpreted by translators as an instruction to ensure that the result of the expression conforms to this type. In Java and C++, this would correspond to a checked type downcast; whereas in Eiffel this would have to be expanded into a reverse assignment attempt. The latter requires an extra variable of the restricted type, to receive the value of the more general type.

An example of type restriction is given below:

<Variable name=”greeting” type=”String” /> <Invoke name=”append” restrict=”String”> <Literal value=”Hello” type=”String” /> <Literal value=” world” type=”String” /> </Invoke></Variable>

Here, it is assumed that the method append is defined generally for any Sequence[T] and returns a result of the static type Sequence[Character] in the String class, which satisfies this interface. However, the context requires the result to be a String, so the value returned by Invoke is restricted from Sequence[Character] to String.

Dynamically, we imagine here that the value returned by append will be of the expected String type, so this restriction will succeed. If the type of the expression does not conform to the restriction, then the translation should raise an exception.

Page 30: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 30

3.2 Identifier Element

The Identifier element denotes a named identifier, such as a variable or field name, which has a bound value in the context of use, so is an atomic expression.

3.2.1 Identifier attributes

The Identifier element declares the following attributes:

name – the name of the identifier, corresponding to an earlier field or variable declaration with the same name;

scope – one of local , object, or special indicating whether it refers to a local variable, an object field, or a special pseudo-variable such as self or super. If absent, local scope is assumed by default (optional).

The scope attribute of an identifier that names a previously declared local variable, or method parameter, is set to local, or is simply omitted (and understood to be local by default). The following two declarations are equivalent:

<Identifier name=”age” scope=”local” />

<Identifier name=”age” />

The scope attribute of an identifier naming a previously declared field is set to object. This distinguishes fields and parameters of the same name:

<Identifier name=”age” scope=”object” />

The scope attribute of an identifier naming the self-object or super-object is set to special, indicating a special pseudo-variable:

<Identifier name=”self” scope=”special” />

<Identifier name=”super” scope=”special” />

The type of an identifier need not be declared, but is resolved by searching for the closest preceding declaration of a field or variable with the same name.

3.3 Literal Element

The Literal element denotes a literal constant value, such as a number, character or string value, which has a simple printed representation.

3.3.1 Literal attributes

The Literal element declares the following attributes:

value – the string representation of the literal value;

type – the type of the literal value, a Basic or Class type.

Some examples include:

Page 31: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 31

<Literal value=”John Smith” type=”String” />

<Literal value=”3.1415926” type=”Decimal” />

<Literal value=”42” type=”Natural” />

<Literal value=”e” type=”Character” />

<Literal value=”false” type=”Boolean” />

The value supplied for the value attribute must always be quoted as a text string, in accordance with XML rules. Certain unusual single character values must be escapedin XML, following XML PCDATA conventions. These include the single- and double-quote characters:

<Literal value=”&apos” type=”Character” />

<Literal value=”&quot” type=”Character” />

The type attribute of a literal expression must always be supplied, so that translators interpret types correctly. For example, “42” could denote a Natural or Integer value; and “c” could denote a Character or String. The type information is also used by translators to demarcate literal values of certain types, e.g. surround char-values with single quotes, or surround strings with double-quotes. Some translators may prefix enumerated values with their type names.

3.3.2 Literal contents

Usually, the Literal element has no further content. However, when a literal value is being used as a case-label in a multi-branching Select expression, it may contain a single sub-expression, typically a Sequence, representing the branch to execute for that case (see also the definition of Select, below):

<Literal value=”sun” type=”Day”> <Operator symbol=”return”> <Literal value=”Today is Sunday” type=”String” /> </Operator></Literal>

3.4 Operator Element

The Operator element denotes an operator expression with one or two operands. Simple unary operators include the return statement, in-place increment, or logical negation. Binary operators include assignment, comparison and arithmetic operators.

3.4.1 Operator attributes

The Operator element declares the attribute:

symbol – the name of the operator symbol, an enumerated value from a list of pre-defined operator symbol names;

The following are legal operator symbol names:

Page 32: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 32

logical operators: not, or, and and implies;

comparison operators: equals, notEquals, lessThan, moreThan , noMoreThanand noLessThan;

arithmetic operators: negate, plus, minus, times, divide and modulo;

mutating operators: assign, increment and decrement;

special operators: return and abort.

Some examples of usage include the assignment-operator setting an object’s field to the value supplied by a method parameter of the same name:

<Operator symbol=”assign”> <Identifier name=”age” scope=”object” /> <Identifier name=”age” /></Operator>

Another example is return-operator, which returns the enclosed value:

<Operator symbol=”return”> <Identifier name=”age” scope=”object” /></Operator>

Most operators are binary expressions, such as the comparison operations:

<Operator symbol=”lessThan”> <Identifier name=”age” /> <Literal value=”18” type=”Natural” /></Operator>

Another example is the arithmetical expression computing the sum of two values, here from a variable and a literal sub-expression:

<Operator symbol=”plus”> <Identifier name=”total” /> <Literal value=”5” type=”Integer” /></Operator>

3.4.2 Operator contents

The contents of an Operator expression consist of one or two sub-expressions. Unary operators may contain one sub-expression. Binary operators contain two sub-expressions, whose order may be significant, e.g. in assignment, the target variable appears first and the source value second, as shown in the example above.

Unary operators: not, negate, return, abort, increment and decrement;

Binary operators: all the remaining operators.

It is assumed that translators will check that operators are always applied to values of suitable types; viz. whereas comparison operators may be applied to any operands that

Page 33: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 33

are comparable, logical operators may only apply to Boolean values and incrementing operators may only apply to Integer or Natural values. Expressions with Void-type cannot therefore be used as sub-expressions of Operator-expressions.

Operator expressions are considered to have a value and type. The value of assignment, increment and decrement operations is always the updated value (there is no equivalent of the pre-increment return value, as in some languages). Assignment is assumed to replace any existing value in the same variable; the CSM expects any unreachable objects to be garbage collected.

The translation of operator expressions may vary from language to language. Some may consider operators to be shorthand for method invocations, and allow the programmer to associate operators with named methods. Some languages allow users to extend the set of operators. Other languages admit a fixed set of operators as primitive kinds of built-in functions that apply only to operands of certain pre-defined types. The CSM assumes a fixed set of operators.

3.5 Invoke Element

The Invoke element denotes the invocation of a named method. A method invocation requires a valid target object expression (which evaluates to an object) and zero or more argument expressions.

3.5.1 Invoke attributes

The Invoke element declares the attributes:

name – the name of the method to invoke, which matches the name of a previously declared Method element;

implicit – true if the target object is implicitly self, in which case no explicit target object expression need be supplied (optional).

A typical canonical example of method invocation on an object stored in a local variable called person is given below:

<Invoke name=”setAge”> <Identifier name=”person” /> <Literal value=”25” type=”Integer /></Invoke>

This has two sub-expressions, the first standing for the target object, and the second representing an argument. The target object may be omitted if a method is understood to be invoked on self, the current object, in which case implicit is set to true. An example of this is shown below.

3.5.2 Invoke contents

The Invoke element contains zero, one or more sub-expressions. If there are no sub-expressions, the target object is implicitly self (the implicit attribute must also be set to true) and the method will be an access method expecting no arguments:

Page 34: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 34

<Invoke name=”getAge” implicit=”true” />

This is the only case where Invoke has no contents at all. There are two ways in which Invoke may contain a single sub-expression. The first is when invoking an access method with no arguments on a target object expression:

<Invoke name=”getAge”> <Identifier name=”person” /></Invoke>

The second is when invoking an update method with a single argument upon the implicit target self, in which case only the argument expression need be supplied. Compare the following self-invocation with the canonical example above:

<Invoke name=”setAge” implicit=”true”> <Literal value=”25” type=”Natural” /></Invoke>

This is equivalent to the slightly longer form containing two sub-expressions, in which the target self is made explicit:

<Invoke name=”setAge”> <Identifier name=”self” scope=”special” /> <Literal value=”25” type=”Natural” /></Invoke>

In all other cases, the Invoke element has multiple sub-expressions, in which the first is always the target object expression (unless the target is implicit) and the remaining sub-expressions are actual arguments supplied to the method (see the canonical example above).

3.6 Create Element

The Create element denotes the invocation of a named constructor. Constructionrequires a variable to initialise and zero or more argument expressions to use as the initial values. The effect is to create a new object, of the same type as the target variable, and initialise it with the supplied arguments. If the variable already contains a valid object reference, this is replaced by a new object reference.

3.6.1 Create attributes

The Create element declares the attributes:

name – the name of the constructor to invoke, which matches the name of a previously declared Creator element;

type – the type of the object being created by the expression, which must also be supplied;

implicit – true if the target object is the surrounding variable or field, which is to be initialised at declaration (optional).

Page 35: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 35

A typical creation expression is shown below, in which the first sub-expression is the target variable and the remaining sub-expressions are initial values:

<Create name=”make” type=”Person”> <Identifier name=”visitor” /> <Literal value=”John” type=”String” /> <Literal value=”Smith” type=”String” /> <Literal value=”25” type=”Integer” /></Create>

This corresponds to setting a local variable visitor to a new instance of the Personclass, supplied with the initial values “John”, “Smith” and “25”. Typically, the target of construction is a newly-declared variable with a null default value. Within a loop, the same variable might be repeatedly constructed with new values. In this case, the CSM supports (eventual) garbage collection of the previous value.

If the implicit attribute is set to true, the first expression standing for the target identifier may be omitted, in which case the Create-expression is understood to be constructing an object in the immediately-surrounding Field or Variable declaration. An example of this is shown below.

3.6.2 Create contents

In general, the contents of a Create element may include the following:

the target variable, to be initialised by the creation expression (optional);

zero or more expressions used as creation arguments (optional).

The shortest kind of Create expression, which has no contents at all, initialises a surrounding Variable as it is declared, using default construction. The implicitattribute must be set to true, to indicate the omitted target:

<Variable name=”newPerson” type=”Person”> <Create name=”make” type=”Person” implicit=”true” /></Variable>

A Create expression should otherwise contain at least a single Identifier sub-expression standing for the target variable; the following assumes that a Variablecalled newPerson was previously defined in the current scope:

<Create name=”make” type=”Person”> <Identifier name=”newPerson” /></Create>

If the target is implicit, the first sub-expression of Create may be a value-expression standing for a construction argument:

<Variable name=”namedPerson” type=”Person”> <Create name=”makeNamed” type=”Person” implicit=”true”> <Literal value=”John” type=”String” /> </Create></Variable>

Page 36: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 36

In general, the Create element has multiple sub-expressions, in which the first is always the target variable identifier (unless the target is implicit) and the remaining sub-expressions are actual arguments (see the canonical example above).

All the above examples assume that the target variable is being initialised with an object of the same type. It is also possible to create an instance of a compatible subclass type in a variable of a given type. To do this, the type-attribute of the Createelement must specify the actual type of the object being created:

<Create name=”makeRegistered” type=”Student”> <Identifier name=”visitor” /> <Literal value=”John” type=”String” /> <Literal value=”Smith” type=”String” /> <Literal value=”25” type=”Integer” /> <Literal value=”6396642909” type=”Integer” /></Create>

This corresponds to setting a local variable visitor to a new instance of the Studentclass, supplied with the initial values “John”, “Smith”, “25” and the registration number “6396642909”. A suitable Creator called makeRegistered must exist in the Student class, and Student must be a subclass of Person, for this to be legal.

A similar principle applies when creating instances of a generic class. If any class declares formal generic parameters, then actual types must be supplied to replace the generic parameters, when instances of this class are created. This is indicated in a Create element by setting the type attribute to the desired instantiated pattern. The following illustrates how to create the Integer instantiation of a generic List class:

<Create name=”make” type=”List[Integer]”> <Identifier name=”intList” /></Create>

This creates an empty instance of List, specialised for the Integer type, in a previously-declared variable named intList. Translators must be able to recognise the square bracket syntax in such instantiated type specifications. In Java and C++, this information would be used in the generation of constructor calls, to replace the formal generic parameters by actual types.

3.7 Sequence Element

The Sequence element is a kind of Compound, a block consisting of a series of statements to be executed in sequence. Optionally, a number of local variable declarations may appear at the head of a sequence.

3.7.1 Sequence contents

The contents of a Sequence element include:

optional local Variable declarations, to be introduced within the current block scope (optional);

Page 37: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 37

one or more Expression elements (typically subtypes of Expression) as the body statements.

A sequence expression always contains at least one sub-expression:

<Sequence> <Operator symbol=”assign”> <Identifier name=”count” scope=”object” /> <Literal value=”5” type=”Integer” /> </Operator></Sequence>

A sequence expression typically contains several sub-expressions, such as the following sequence of assignments:

<Sequence> <Operator symbol=”assign”> <Identifier name=”forename” scope=”object” /> <Literal value=”John” type=”String” /> </Operator> <Operator symbol=”assign”> <Identifier name=”surname” scope=”object” /> <Literal value=”Smith” type=”String” /> </Operator></Sequence>

A sequence expression may have a result, if it contains a return-statement, which should appear as the last expression in the sequence:

<Sequence> <Operator symbol=”assign”> <Identifier name=”total” /> <Literal value=”10” type=”Integer” /> </Operator> <Operator symbol=”return”> <Identifier name=”total” /> </Operator></Sequence>

This is typical if the sequence is the body of a method that returns a value, or if the sequence is a branch in a Select-expression, where all branches return a different value. Finally, a sequence may declare one or more local variables at the start, which remain in scope only for the duration of the sequence:

<Sequence> <Variable name=”local” type=”Integer” /> <Operator symbol=”assign”> <Identifier name=”local” /> <Literal value=”20” type=”Integer” /> </Operator> <Operator symbol=”return”> <Identifier name=”local” /> </Operator></Sequence>

Page 38: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 38

Here, a variable named local is declared, which exists for the duration of the sequence, but goes out of scope at the end.

3.8 Parallel Element

The Parallel element is a kind of Compound, a block whose sub-expressions are all executed in parallel. This provides a facility for multi-thread programming in OOP, which may be translated in languages supporting parallel execution. The standard interpretation in the CSM is that a concurrent fork is initiated by a Parallel element, which re-synchronises at the end of the Parallel element, which is interpreted as a concurrent join. If a language does not support parallel execution, then the CSM allows a Parallel block to be executed exactly as a Sequence block, which is a special case of parallel interleaving.

Optionally, a number of local variables may be declared at the head of a parallel block, which may be used as communication channels between the different processes. The CSM assumes that such variables are always locked when they are updated or read by any process within the parallel block.

3.8.1 Parallel contents

The contents of a Parallel element are identical to those of a Sequence element (see section 3.6.1 above); it is only the execution semantics that are different. The following example invokes two procedural methods in parallel, whose effects are assumed to be non-intersecting:

<Parallel> <Invoke name=”debitAccount”> <Identifier name=”bank” /> <Identifier name=”number” /> <Identifier name=”amount” /> </Invoke> <Invoke name=”dispenseCash”> <Identifier name=”dispenser” /> <Identifier name=”amount” /> </Invoke></Parallel>

The following example returns zero, or five, non-deterministically, depending on the order in which the parallel threads access the shared variable count:

<Parallel> <Variable name=”count” type=”Integer” value=”0” /> <Operator symbol=”assign”> <Identifier name=”count” /> <Literal value=”5” type=”Integer” /> </Operator> <Operator name=”return”> <Identifier name=”count” /> </Operator></Parallel>

Page 39: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 39

The synchronised variable count is initialised before the concurrent fork. Synchronised objects can be constructed using the extended Variable initialisation syntax (see the definition of Variable above).

3.9 Select Element

The Select element is a kind of Control statement, denoting a single, dual or multi-branch choice. This construction models both if-then-else and switch (case in Delphi, inspect in Eiffel) statements. If the branches of the select-expression contain return-statements, then it is considered to have a resulting value.

3.9.1 Select attributes

A Select element has a single attribute:

choice – is one of simple or multiple, to distinguish simple if-then-else choices from more complex multi-way selection with case labels.

See examples of usage of each of these below.

3.9.2 Select contents

A Select element contains two, three or many sub-expressions. The first sub-expression is always the choice-expression and the remaining sub-expressions are the branches. The choice-expression is evaluated to determine which branch to take. In a simple selection, the contents are:

a Boolean choice-expression yielding true or false;

the then-expression to select when true;

the else-expression to select when false (optional).

The following example is of a single-branching selection, surrounding an optional expression to perform if the condition-expression has the value true:

<Select choice=”simple”> <Operator symbol=”noMoreThan”> <Identifier name=”amount” /> <Identifier name=”balance” /> </Operator> <Invoke name=”debitAmount”> <Identifier name=”account” /> <Identifier name=”amount” /> </Invoke></Select>

If the amount is no more than (less than, or equal to) the balance, then this amountmay be debited from the account.

Page 40: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 40

The following example is of a dual-branching selection, corresponding to an if-statement with both a then- and an else-branch. The then-branch always appears immediately after the condition-expression, and the else-branch always appears last:

<Select choice=”simple”> <Operator symbol=”noMoreThan”> <Identifier name=”amount” /> <Identifier name=”balance” /> </Operator> <Invoke name=”debitAmount”> <Identifier name=”account” /> <Identifier name=”amount” /> </Invoke> <Invoke name=”displayWarning” implicit=”true” /></Select>

If the amount is no more than the balance, this amount is debited from the account, otherwise the current object self displays a warning message.

For a multiple selection, the contents of a Select element are styled differently:

the choice-expression, yielding a scalar value;

multiple branch-expressions, guarded by case labels.

This time, the choice-expression yields a scalar value. This can be an integral or character value, or an enumerated constant. This value is used to select a unique branch to execute. Each further sub-expression is a branch, which must be guardedby a unique case label for that branch. This is a Literal value (see Literal, above), whose content is the actual expression (typically a Sequence) to execute when the guard is matched:

<Select choice=”multiple”> <Invoke name=”getToday” /> <Identifier name=”calendar” /> </Invoke> <Literal value=”sun” type=”Day”> <Invoke name=”printLine”> <Identifier name=”output” /> <Literal value=”The day is Sunday” type=”String” /> </Invoke> </Literal> <!—- similar selection branches for Monday, Tuesday Wednesday, Thursday, Friday inserted here --> <Literal value=”sat” type=”Day”> <Invoke name=”printLine”>

<Identifier name=”output” /> <Literal value=”The day is Saturday” type=”String” /> </Invoke> </Literal></Select>

In the above multi-branching selection, it is assumed that the choice-expression returns an enumerated value from the type Day, in the range {sun, mon, ... sat}. Each

Page 41: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 41

of the branch-expressions is wrapped with a Literal element, denoting one of the enumerated case-labels. Note that the type of each case-label must correspond to the type of the choice-expression; and only scalar values may be used for case labels. The branches are expected to be an exhaustive enumeration of all possible cases.

In the CSM, each branch is a strict alternative to the other branches. There is no possibility of “falling-through” the different cases, as with switch-statements (in Java, C++). This means that translators for these languages must insert break statements after branches that do not already end with a return statement. Likewise, there is no default branch; although translators are free to insert a default branch reporting an exception that the selection failed to handle all cases.

3.10 Iterate Element

The Iterate element is a kind of Control statement, denoting a conditional or deterministic loop. This construct models test-first while, for and foreach loops (in languages like Java, C#, C++) and from-until loops (in Eiffel). There is no equivalent of the test-last do-while loop (in Java, C++) or repeat-until loop (Delphi).

3.10.1 Iterate attributes

The Iterate element declares the following attribute, which determines what kind of iteration will be undertaken:

loop – one of dynamic or bounded, indicating whether the iteration is conditional, or deterministic.

The value dynamic indicates an unbounded iteration, corresponding to a test-firstwhile loop, in which the continuation condition is tested before commencing each iteration. Some target languages, such as Eiffel, may expect a halting condition instead; and so translators must reverse the logical condition in this case.

The value bounded indicates a bounded iteration over a fixed range of values. This may correspond either to a for-loop, in which a counter variable ranges over a fixed number of values, or a foreach-loop, in which an iteration variable ranges over each individual element in a collection. Translators for target languages without foreach-loops must find a workaround involving iterators.

3.10.2 Iterate contents

The Iterate element contains two sub-expressions. For the conditional dynamiciteration, these are:

the loop continuation condition, an expression yielding true or false;

the loop body expression, including suitable update expressions.

An example of a conditional loop is shown below. This assumes that a set is having elements inserted until it reaches a given size. The loop will continue to iterate so long as the size is less than some previously specified maximum value. The body of the loop contains an operation to add elements uniquely to the set:

Page 42: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 42

<Iterate loop=”dynamic”> <Operator symbol=”lessThan”> <Invoke name=”size”> <Identifier name=”set” /> </Invoke> <Identifier name=”maximum” /> </Operator> <Sequence> <Variable name=”item” type=”Element”> <Invoke name=”getNextItem” implicit=”true” /> </Variable> <Invoke name=”add”> <Identifier name=”set” /> <Identifier name=”item” /> </Invoke> </Sequence></Iterate>

A dynamic iteration is used when the number of iterations cannot be determined in advance, but depends on some embedded condition. In this example, it is impossible to tell in advance whether the set will increase in size upon each iteration, since this depends on the item added (whether it was already a member of the set, or not).

The preferred translation of a dynamic iteration is into a while-loop in the target programming language. The body of the loop must always contain some expression which (eventually) modifies the value of the loop condition, such that the loop terminates; however, this cannot be guaranteed from a static analysis.

For the deterministic bounded iteration, the contents of an Iterate element are:

a loop Variable declaration, with an initial range specification, from which the continuation condition may be determined automatically;

the loop body expression, which may refer to, but should not attempt to update, the variable.

When using a Variable element as a loop iteration variable, the range attribute (see Variable, above) must be specified to have one of the following values:

rising – a counted iteration which increments the variable on each iteration;

falling – a counted iteration which decrements the variable on each iteration;

foreach – a bounded iteration which ranges over every element of a collection.

For counted iterations, the Variable must have one of the types Natural or Integer and the range must always be specified as one of rising or falling. This determines whether the iteration variable will be incremented, or decremented upon each iteration. The contents of the Variable should then specify an initial value, and an upper or lower limit (excluded from the iteration), for example:

Page 43: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 43

<Iterate loop=”bounded”> <Variable name=”counter” type=”Natural” range=”rising”> <Literal value=”0” type=”Natural” /> <Literal value=”5” type=”Natural” /> </Variable> <!-- loop body expression inserted here --></Iterate>

This iteration initialises a variable called counter to zero, and repeats the loop body five times, incrementing the counter on each iteration, up to but not including the limit five. The limit is a backstop, always one step beyond the range of the iteration. The loop body may refer to the counter, but should not modify this variable independently. The above rising iteration may be specified more succinctly as:

<Iterate loop=”bounded”> <Variable name=”counter” type=”Natural” range=”rising” value=”0” limit=”5” /> <!-- loop body expression inserted here --></Iterate>

This uses the attributes: value to declare the initial value; and limit to declare the upper limit of the iteration. This short-hand may only be used if the value and limitare simple scalar values.

By specifying that the loop Variable’s range attribute is falling, it is possible to construct loops that decrement the variable, down to a lower limit:

<Iterate loop=”bounded”> <Variable name=”counter” type=”Natural” range=”falling” value=”5” limit=”0” /> <!-- loop body expression inserted here --></Iterate>

These initialise counter to five, and repeat the loop body five times, decrementing the counter on each iteration, up to but not including the limit zero. Where the contents of a Variable contain two sub-expressions, the initial value always appears first, and the limit appears second.

If the Variable’s range-attribute is specified as foreach, this indicates bounded iteration over every element of a collection. The Variable will contain one sub-expression, which must evaluate to a collection (on which iteration is defined). The variable is initialised to the first element in this collection, and will iterate over a different element on each cycle, until the whole collection has been traversed. If the collection is empty, no action is taken. For example:

<Iterate loop=”bounded”> <Variable name=”employee” type=”Person” range=”foreach"> <Invoke name=”getEmployees”> <Literal name=”company” /> </Invoke> </Variable> <!-- loop body expression inserted here --></Iterate>

Page 44: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 44

The above example invokes getEmployees() on the object stored in company, and binds the loop variable employee to each Person instance in turn. The loop body is written in terms of operations to be performed on each employee individually.

Translations will either use languages that support the foreach-loop (such as Java, C#), or have a boilerplate coding strategy to convert this into explicit iteration statements over the collection. All of the bounded forms of loop are guaranteed to terminate, assuming that the returned collection is not infinite.

3.11 Assert Element

The Assert element serves to describe an executable assertion, such as a precondition, postcondition, data type invariant, loop invariant or arbitrary assertion check. Assertions contain a Boolean-valued expression, which should hold true when evaluated. If the asserted condition does not hold, an exception is raised. For this reason, the Assert element is a kind of Control statement.

3.11.1 Assert attributes

The Assert element declares the following attribute:

label – a short string describing the asserted property.

The label attribute describes the positive property that the assertion is checking. This is most useful when translating assertions into Eiffel, which uses labels as a way of identifying broken assertions in system stack traces. The label may also serve as a message string in Java-style exception objects.

3.11.2 Assert contents

The contents of an Assert element include:

the assertion expression, a Boolean-valued property being asserted.

The following is an example of a precondition on an insert-method that checks for a valid (non-null) element before this is inserted into a collection of some kind:

<Method name=”insert” type=”Void” visible=”public”> <Variable name=”item” type=”Element” /> <Assert label=”valid item”> <Operator symbol=”notEquals”> <Identifier name=”item” /> <Literal value=”null” type=”Null” /> </Operator> </Assert> <!-- method body inserted here --></Method>

This asserts a property labelled “valid item”, which is checked using the contained assertion expression. This is an operator expression, which checks that the itemvariable is not equal to null. If this property is violated (the assertion expression

Page 45: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 45

yields false), then a standard exception is raised. Translations should try to preserve the label, for example, as an argument to the constructed exception.

3.11.3 Assert invariants, pre- and postconditions

Assert elements may be included in three places:

in the declaration of a class (or interface, in the ESM) – in this case, the assertion is interpreted as a data type invariant, which must hold for all objects created of this type;

in the declaration of a method or constructor – in this case, the assertion is interpreted as a precondition, which must hold before the body is invoked;

in a method or constructor body expression, anywhere that a Control statement is legitimate – in this case, the assertion is interpreted as a checked condition, or as a postcondition, which must hold when the body terminates.

The difference is in the way that exceptions are handled, when the asserted property is broken. Following Eiffel’s programming by contract rule, whereas broken invariants and failed postconditions are the responsibility of the currently executing method (or constructor), failed preconditions return control to the caller (since the currently executing method is not at fault).

Preconditions translate smoothly into Eiffel as require-clauses. In Java or C++, they translate into conditions throwing (locally uncaught) exceptions. Postconditions translate smoothly into Eiffel as ensure-clauses. In Java or C++, they translate into conditions throwing locally-caught exceptions. To achieve this, the remaining method body must be protected by a try-block (this allows a following catch-block to handle them). Invariants translate smoothly into Eiffel as invariant-clauses. In other languages, they must become protected methods, invoked at an appropriate point (typically, as the last statement) in all state-modifying methods of the owner.

3.12 Rescue Element

The Rescue element serves to describe exception handlers. A single Rescue element may occur at the end of the body of a method or constructor, to handle all exceptions raised during the body. The statements contained within a Rescue element typically clean up the faulty state of the application. After cleaning up, the operation may either fail gracefully, passing control to the next outermost handler, or may attempt to resume execution, by repeating the failed operation (like Eiffel).

3.12.1 Rescue attributes

The Rescue element declares the attribute:

attempts – a positive integer n, indicating that a rescue should be attempted up to a maximum of n times (optional).

If attempts is greater than zero, the failed method or constructor will be re-attempted up to this number of times, after cleaning up the local state in the Rescue-body;

Page 46: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 46

otherwise the failure will be passed immediately up the stack. The context of a rescued method or constructor body may assume the existence of a special Integervariable, attempts, which is initialised to zero on the first (original) attempt and incremented towards the maximum number of attempts (excluding this value), on each resumption. If this limit is reached, the failure is passed up the stack, where further attempts may be made to fix the problem.

3.12.2 Rescue contents

The Rescue element contains the following:

an Expression element, typically a Sequence, describing how to clean up the local state.

If the Rescue block eventually fails, the failure is passed up the stack to the next caller, which may be able to address the failure. This behaviour continues recursively, unwinding the stack, until the top level is reached, in which case the system terminates and the stack trace is reported to the user.

If the Rescue block resumes execution, this is interpreted as a request to re-start the failed method. Translations are encouraged to find iterative solutions to re-attempting failed methods. The context of resumption may only assume revised object fields and method arguments. No other assumption may be made about the values of local variables, apart from the existence of attempts (local variables may be re-bound at re-entry). In Eiffel, a Rescue block translates into a rescue clause with optional retryinstruction; in Java, C# and C++, this translates into a surrounding try-catch block, optionally surrounded by a while-loop to handle repeated attempts.

An example of recovery is in the following method that repairs any precondition failure of the earlier insert method (see above):

<Method name=”testInsert” type=”Void” visible=”public”> <Variable name=”item” type=”Element” /> <Sequence> <Invoke name=”insert”> <Identifier name=”collection” scope=”object” /> <Identifier name=”item” /> </Invoke> <Rescue attempts=”1”> <Create name=”make” type=Element> <Identifier name=”item” /> </Create> </Rescue> </Sequence></Method>

The method testInsert accepts an item, and attempts to insert this into a collection known to the current object. If item = null, then the precondition to insert is broken (see above). Control jumps to the rescue-block, which constructs a new instance of Element in item, then resumes. This causes testInsert to start afresh, this time with a valid item.

Page 47: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 47

4. OOP System Construction

The complete model for system generation takes into account the different styles in different programming languages. This includes different approaches to constructingthe “main program”, some conventions to follow when importing native library code and the adoption of boilerplate coding techniques for specific languages, to help implement the CSM.

4.1 The Main Program

How are code generators expected to assemble complete systems? In principle, we adhere to Meyer’s tenet that “real systems have no top”, that is, we should expect the main function of an object-oriented system to change from time to time; indeed, for there to be possibly many different entry points into the system. However, there is a mismatch between this and the coding styles supported in some target languages.

In languages influenced by C, there is expected to be a main procedure which sits outside the object-oriented model; whereas in Java this is finessed as a static method called main() belonging to any class which may serve as a root object of the application. We do not admit a static main() method in the pure object-oriented model of OOP, since this technically represents a global procedure to be executedindependently of object creation.

4.1.1 System entry points

The solution adopted for OOP follows the Command design pattern (Gamma, et al., 1995), in which any class wishing to encapsulate an executing system provides a method named execute(). In this way, more than one class may serve as the entry point, so long as the generation tools know which class to use, when building the system. In our approach, any class that wishes to serve as an entry point must alsospecify a default constructor named create() that takes no arguments:

<Class name=”SomeClass”> <!-- other fields and methods of SomeClass --> <Creator name=”create” type=”SomeClass”> <!-- contents of the default constructor --> </Creator> <Method name=”execute”> <!-- contents of the driver procedure --> </Method></Class>

The create() constructor is responsible for creating and initialising the other objects that constitute the system. The execute() method initiates processing among the objects of the system. Whereas Eiffel has a similar approach, in which a root constructor creates and also initiates the system, we prefer to distinguish constructingthe system from executing it, treating these as separate steps, since in certain languages (such as C++), it is problematic to think of executing a system that has not yet finished being constructed.

Page 48: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 48

4.1.2 Translation of entry points

The preferred translation strategy for a system entry point is to create an instance of the chosen root class. For example, assume that SomeClass has a create() constructorin OOP. In Java, this translates into a default constructor and a static main() method. In Java, each entry point class may have a main() method and it is only on the command-line that the chosen root class is selected:

public class SomeClass {

public static void main(String[] args) { SomeClass root = new SomeClass(); root.execute();}

public SomeClass() { // construct other objects}

public void execute() { // initiate other processing}

}

This program would be launched, after compilation, by the command:

java SomeClass

On the other hand, a C++ translation might generate a standard program file main.cpp, which creates an instance of the chosen root object. In C++, there has to be a separate main program file, is because it is illegal to have more than one main() procedure in a collection of compiled files. Here is an outline for main.cpp:

#include “SomeClass.h”

int main(int argc, char** argv) { Ref<SomeClass> root = new SomeClass(); root->execute(); return 0;}

This ensures that the system root class is properly constructed and, in this translation, stored in a smart pointer variable, such that, if exceptions are raised while executing the system, the resources of the system will still be reclaimed when the smart pointer goes out of scope.

In Eiffel, the execution model follows the OOP model very closely. The system is executed by creating an instance of the chosen root class. The translation must ensure that a call to execute() is placed as the last instruction in the create() constructor. When running the Eiffel compiler for the first time, a configuration file (ACE file) is generated, which may then be edited to allow the user to specify the root class and which root creation procedure to call.

Page 49: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 49

4.2 Using Library Code

Ideally, the set of classes constituting the evolving part of the system is a subset of all the classes required to build the system. ReMoDeL tools should not have to generate code for everything down to the level of standard library classes (such as strings, buffers and streams) but rather generate code down to a level at which standard library classes are provided already in the target language.

4.2.1 Library class interfaces

The standard way of referring to predefined classes in a target language is to specify in ReMoDeL OOP the signature of the library class. One of the attributes of the Classelement is the library attribute, which, when set to true, indicates that the class described is predefined in the library. This implies that tools need not generate code from the Class description (since standard code exists), but also means that the library Class only declares fields and method signatures, similar to an interface. In OOP, the library Class specification is used for two purposes:

to determine the location of the library class;

to support type checking against library class methods.

Note that library classes must be placed in packages that are somehow language-neutral for this to work; this may involve construction of special packages in each target language that group the desired elements accordingly, importing them from their own package structures. An example might be:

<Package name=”Core” model=”OOP” location=”lib.core” /> <Basic name=”Integer” library=”true” /> <Class name=”String” library=”true”> <Method name=”append” type=”String”> <Variable name=”other” type=”String” /> </Method> <!—- other methods of String --> </Class></Package>

This defines a Core package, in a neutral location “lib.core”, which contains the Integer and String library classes. The Integer basic type is just mentioned by name, without any body, since the operations on integers are predefined. The String class declares a number of methods, including append(String) which returns a String result. Note that the body of this method is empty, since it describes an interface. This allows checking tools to determine that calls in other OOP code are correctly typed on the library String.

4.2.2 Special purpose libraries

The above Package is assumed to exist in a language-neutral location “lib.core”, which is not necessarily a standard directory in any of the target languages. There are three possible approaches to dealing with this:

Page 50: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 50

the target language allows you to pre-import standard classes from language-specific locations into these neutral locations, from where they are accessed by the ReMoDeL generators;

a special standard library is created for the target language in the given neutral location, containing class definitions that shadow library implementations,which are stored in their language-specific locations;

the translation tools take special note of package names such as “Core” and arrange to convert the neutral package location into a language-specific location; e.g. the location “lib.core” might translate to “java.lang” in Java.

In practice, the second option is likely, since this allows the creation of standard wrapper versions of common library types, such as String, with a standard core interface that maps onto the different underlying string types supported in languages as diverse as C++, Eiffel and Java. Every effort should be made to ensure that this is as efficient as possible.

4.3 Implementing Dynamic Object Management

The CSM deliberately adopts the more dynamic view of objects, which are freely created and deleted, with features like polymorphic aliasing, safe type downcasting and garbage collection. Each of the target languages must support this model. In certain target languages, such as Java, these features are already built-in to the native programming model. In other languages, this requires the provision of a base library of some sophistication. An example of this in C++ is given below.

4.3.1 Mark-and-sweep garbage collector

To implement dynamic objects with uniform reference semantics in C++ requires the use of object allocation on the heap, with some form of memory management to ensure that unused objects are deleted afterwards. One possibility is to include a garbage collector for C++ (several implementations exist). In this translation model, all field and variable types become C++ pointer types:

SomeClass* ptr = new SomeClass();

and the garbage collector performs occasional sweeps through heap memory to determine whether variables are still reachable from current stack memory. This is a good option if a garbage collector with predictable performance characteristics is available. Mark-and-sweep collectors may execute at unpredictable intervals and may suspend normal execution while collecting.

4.3.2 Reference-counted memory management

Alternatively, a reference-counted memory management policy is possible, through the creation of smart pointers. In this translation model, all field and variable types become smart pointer types, and objects are assigned immediately to smart pointers upon creation, so that their lifetime may be managed:

Ref<SomeClass> ptr = new SomeClass();

Page 51: ReMoDeL - Sheffieldstaff€¦ · Java, C++, C#, Eiffel) in a language-neutral way; and that it should be possible to translate from OOP models into executable code in any of these

ReMoDeL: OOP Specification, 26 March 2010 51

The smart pointer type Ref<T> is a template class, parameterised by the type T of the object stored in it. In this model, all objects contain a reference count, which is incremented or decremented as that object is assigned to, or forgotten by, a smart pointer. When the reference count reaches zero, the object is deleted. This model is good for incremental garbage collection. The only disadvantage is the need to handle circular referencing explicitly, to ensure that mutually-supporting objects are eventually deleted.

4.3.3 Safe type upcasting and downcasting

Another advantage of the template-based policy in C++ is the ability to provide built-in type casting for smart pointers of different types. There are two policies that can be implemented in C++:

allow automatic upcasting, but prohibit implicit type downcasting;

provide checked upcasting and downcasting, with raised exceptions.

The first of these policies uses member templates, for example, the smart pointer constructor and assignment operator would have the following overloaded possibilities accepting other pointer types Ref<S> :

template <class T> template<class S>Ref<T>::Ref(const Ref<S>& ref)

template<class T> template<class S>Ref<T>& Ref<T>::operator = (const Ref<S>& ref);

in addition to the usual versions that accept a Ref<T> argument. The statically checked bodies will allow automatic upcasting from Ref<S> to Ref<T> (derived by determining that S* may be promoted to T*), but will prohibit unsafe casting.

In the second policy, the bodies perform an explicit dynamic_cast<T*>() on the argument’s raw pointer, raising a type cast exception if the actual S* is not in fact compatible with T*. This has the advantage of not requiring the programmer to generate any explicit type-casts, at the expense of checking all assignments of dissimilar types (whether upcasting, or downcasting).