Home

 

Getting Started with Elisa

Using EDS

Demo's

Tutorials

 

Language Description

1. Lexical Elements
2. Basic Data Types and Expressions
3. Definitions
4. Streams
5. Backtracking
6. Statements and Special Expressions
7. Arrays
8. Lists
9. Descriptors
10. Components
11. Collections
12. Generic Components
13. Terms
14. Categories
15. Types 

16. Built-in Definitions
17. Higher-order Definitions

18. External Interfaces

Index

Data Structures

1. Sequences
2. Examples involving Lists
3. Trees
4. Graphs
5. Searching State Spaces
6. Language Processing
7. Knowledge Representations          

 

Metaprogramming

1. Introduction
2. What are Domain Definitions?

3.  Sorts of Domain Definitions

4.  Manipulations of Domain Definitions

5.  Translating Domain Definitions

6.  Dialogue Sessions

7.  Example of Concentric Circles

8.  Example of Domain Substitution applied to Concentric Circles

9.  Example of an Order Processing Application

10.Example of an Airport Information System

11.Example of a Rental Boat Business

12.Benefits of Domain Definitions

   

Back Home Up Next


1 DOMAIN MODELING

 

1.1 Classification of Models
1.2 Domain Models
1.3 Steps in Domain Modeling
1.4 Results of Domain Modeling
1.5 Moving to Systems Design
1.6 Summary

 

Models have become widely accepted as a means for studying complex phenomena. A model is an abstracted representation of a system. The value of a model arises from its improving our understanding of unclear behavior characteristics more effectively than could be done by observing the real system. A model, compared to the real system it represents, can yield important information about the behavior of the system under different conditions. Models can be a basis for investigations at lower cost and in less time than analyzing actual systems. Knowledge can be obtained more quickly and for conditions not observable in real life.

The main reason for modeling is to deal with systems that are too complex to understand directly. Models reduce complexity by separating out a small number of important aspects to deal with at a time. Models can also be used for experiments under different conditions.

In this part of the book we will examine how modeling can be applied to complex software systems. We start with this chapter about a specific form of modeling, called domain model which is focused on the underlying concepts of a software system.

Metaprogramming with Domain Definitions

In this paper, a novel approach of metaprogramming is introduced based on so-called domain definitions. Domain definitions are describing the characteristics of concepts in a problem domain and are used as input of the metaprocessor. The metaprocessor generates source code, which can be used as input of a compiler. In this article we explain how metaprogramming can be applied to generate  skeleton source code based on declarative domain definitions and how this source code can be used to create executable programs. Several practical examples are given to explain the different software development phases and to illustrate some applications of domain definitions.

In this paper, a novel approach of metaprogramming is introduced based on so-called domain definitions. Domain definitions are describing the characteristics of concepts in a problem domain and are used as input of the metaprocessor. The metaprocessor generates source code, which can be used as input of a compiler. In this article we explain how metaprogramming can be applied to generate  skeleton source code based on declarative domain definitions and how this source code can be used to create executable programs. Several practical examples are given to explain the different software development phases and to illustrate some applications of domain definitions.

 1.  Introduction

There are many different for ms of metaprogramming. In general, metaprogramming is writing programs that generate other programs. In this article we will explain a particular form of program transformation that will show how metaprogramming can be used to generate high-level executable source code based on declarative domain definitions.

     Domain definitions are describing the domains of a problem and are used as input of the metaprocessor. The metaprocessor generates source code that can be used as input of a compiler. In our case the current implementation uses the Elisa language [13, 14, 15] as the target language.

    We will explain what domain definitions are, how they can be used to generate program text, how this text can be tested and what the benefits are of this approach.

2.  What are Domain Definitions?

We will define a domain as the representation of a concept in the computer. Concepts are abstract notions of things in the real world or in a problem area. Because we want to model concepts in such a way that a computer can understand them, we need a method to represent those concepts in a program. For that purpose we will use domain definitions.

     Before domain definitions can be defined, first the key concepts in the problem domain should be identified. To illustrate the steps one has to make in domain orientation we will develop a set of domain definitions for families. We know from daily experience that a family may consist of a father, a mother, and possibly a number of children. So, the key concepts of our family are: father, mother, and children.

     After the key concepts have been identified the corresponding domain definition can be specified. In our example, this is very simple:

Family = Father + Mother + Children;

 This is an example of one of the different forms a domain definition may take. In this domain definition, the domain of Family is defined by using three other domains that should also be defined:

Father = Person;

Mother = Person;

Children = collection ( Person ) ;

These domain definitions are based on a common domain, called Person. In daily life, persons are characterized by name, address, birth date, and so on.  However, to keep our example simple we will define:

  Person = text;

It says that a Person domain is characterized by a piece of text. Finally we need to define the domain of text by:

text = predefined;

This defines text as a predefined domain. Predefined domains cannot further be redefined. They are known to the system. The result of this exercise is a set of related domain definitions describing a family:

Family = Father + Mother + Children;

Father = Person;

Mother = Person;

Children = collection ( Person ) ;

Person = text;

text = predefined;

  This set of domain definitions is sufficient to generate a skeleton source program, as will be demonstrated later on.

3.  Sorts of Domain Definitions

There are different sorts of domain definitions. The following sorts are distinguished:

      1.        Compound domain definitions

2.        Alternative domain definitions

3.        Collection domain definitions

4.        Enumeration domain definitions

5.        Sub-domain definitions

6.        Equivalent domain definitions

7.        Predefined domain definitions

Each definition consists of a name followed by a ‘=’ character, followed by the remaining part of the definition. The remaining part determines the sort of the domain definition and is closed by a semicolon. The order of domain definitions is not important. Text between << and >> is comment.

In the following sections the different sorts of domain definitions will be described.  

3.1 Compound Domain definitions ;

A compound domain definition is composed of references to other domain definitions. These references are names of other domain definitions and are called the elements of the compound domain. The elements are separated by the ‘+’ character. For example, the following domain definitions of Person, Name, Address, and Date are compound domain definitions: 

Person   = Name + Address + Birthdate;

Name     = Firstname + Familyname;

Address = Street + City + State;

Date       = Year + Month + Day;

 3.2 Alternative Domain definitions

An alternative domain definition consists of a number of references to other domain definitions. The references are separated by the ‘|’ (or) character. For example, we take the concept of a customer. A customer of a company may be a person or an organization. This can be expressed in the following way:

Customer = Person | Organization;

In this example, Customer is an alternative domain. This definition may be read as: A customer is a person or an organization. If we assume that the domain of a Person is already defined, then only the domain of Organization need to be defined. This must be the name of another compound domain. For example, Organization can be defined as:

 Organization = Name + Address;

3.3 Collection Domain definitions

A collection domain definition specifies a collection of domains. In an earlier example we introduced Children as a collection of Persons: 

Children = collection (Person) ;

The collection phrase may be read as “zero or more”, or as “some number of” Persons.

Let us use another example. We assume that a company consists of a number of divisions and that each division consists of a number of departments and that each department has a number of employees.

 

Company       = collection (Division);

Division          = collection (Department);

Department   = collection (Employee);

Employee       = Person;

Domain definitions may also be recursively defined. For example, a machine consists of a number of parts; the parts themselves may consists of other parts, and so on, as defined by: 

machine = machinename + collection (part);

part = partname + subparts;

subparts = collection (part);

Parts are recursively defined via subparts. The recursion stops as soon as a part has a partname but no subparts.

 

3.4 Enumeration Domain definitions

An enumeration domain represents a distinct number of elements. Those elements are enumerated by the domain definition. As an example of an enumeration domain we specify the main wind directions:

 

Direction = enum (North,  East, South, West);

Note, that North, East, South, and West are names of elements of the Direction domain; they are not names of other domain definitions. As another example, let us assume that a person is also characterized by its Gender:

 

Person = Name + Birthdate + Gender;

The gender domain can be defined as an enumeration domain with only two elements:

 

Gender = enum (Male, Female);

3.5 Sub-domain definitions

A sub-domain is a domain that represents a subset of all possible elements of a given domain. For example, money can be defined as a sub-domain of real numbers.

 

Money = subdomain (real);

real      = predefined;

Based on these domain definitions we may define the dollar and the euro:

 

Dollar = subdomain (Money);

Euro   =  subdomain (Money);

3.6 Equivalent Domain definitions

A domain can be defined to be equivalent to another domain. For example, client may be another name for customer. This may be expressed as:

 

Client = Customer;

In this example, the client domain is equivalent to the customer domain.

Caution: If clients are special customers then the domain of client is a sub-domain of customer and should be defined accordingly.

 

3.7 Predefined Domain definitions

Predefined domain definitions are domain definitions that can directly be represented in Elisa[14]. Therefore they need no further definitions. The predefined domain definitions in our current implementation are:

 

boolean

character

integer

real

text

term

symbol

4.  Manipulations of Domain Definitions

 

The translation of concepts into domain definitions is not always a straightforward process. In practical situations, domain definitions are rearranged, or redefined, before a satisfactory set of domain definitions is derived.

After the key concepts of a program have been translated into corresponding domain definitions, it is quite likely that you want to revise the set of domain definitions, either by changing the original definitions or by adding or deleting domain definitions. The result of these manipulations should be a complete and consistent set of definitions. Each definition must be compatible with the syntax of one of the sorts of the listed domain definitions. This means, for example, that the + operator and the | operator may not be mixed in the final version of a domain definition. In this section we will examine two techniques for formal manipulation of domain definitions.

 

4.1 Substitution of Domain Definitions

The name of a domain in the right hand part of a definition may be substituted by its definition. So, in a set of domain definitions for Person, we may substitute the definitions for Name, Address, and Birthdate:

 

Person     = Name + Address + Birthdate;

Name       = Firstname + Familyname;

Address   = Street + City + State;

Birthdate = Date;

  Substitution gives us:

 

Person = (Firstname + Familyname) + (Street +  City + State) + Date;

We use parentheses to group domains together; they do not effect the result. The definition is equivalent to:

 

Person = Firstname + Familyname + Street  + City + State + Date;

 By means of this substitution we created a compound Person domain with 6 elements. However, we have lost by this substitution the concepts of Name, Address and Birthdate. Sometimes, this is what we want, because fewer concepts may help to simplify the model. But, sometimes substitution does not help to simplify the model; on the contrary, the loss of a domain name also means losing its semantic meaning. In our example, Date may be interpreted in many different ways, such as birth date, the date when moved to the current address, the date of marriage, and so on. Because Birthdate has a clear meaning, it should not have been substituted.

     That substitution can be pushed too far will be even clearer if we continue our substitution process until all domain references have been replaced by their definitions. If we assume that the final domains are all text domains the result will be:

Person = text + text + text + text + text + text;

In this definition all semantic information has disappeared. It is a domain definition without any meaning. So, substitution at the level of the predefined domains makes no sense. 

4.2 Introduction of New Domain Definitions

It is also possible to do the inverse of substitution: define new domain definitions and use these new domain names to simplify existing domain definitions. Suppose we have the following domain definitions:

 

Truck = Make + Year + Mileage + CargoCapacity;

Bus     = Make + Year + Mileage + PassengerCapacity;

These two domain definitions have a number of common domain definitions. We can introduce an additional domain representing the common domain definitions and rewrite the other domain definitions as follows:

 

Automobile = Make + Year + Mileage;

Truck = Automobile + CargoCapacity;

Bus = Automobile + PassengerCapacity;

  In general, introducing a new domain can be useful if the new domain represents a concept that makes sense in the problem domain. Particularly, if the new domain represents a concept belonging to a hierarchy of concepts, as in our example. On the other hand, the introduction of new domain definitions that do not represent concepts in the problem domain may cause problems in successive modeling steps.

 

5. Translating Domain Definitions

 

The metaprocessor is a key component of the metaprocessing system. It has as input a set of related domain definitions. The output is a skeleton of a source program. Our current implementation generates a skeleton of an Elisa program. To demonstrate the process of metaprocessing we return to our Family program and formulate a complete set of domain definitions. See Figure 1.


Family        = Father + Mother + Children;

Father        = Person;

Mother       = Person;

Children     = collection (Person);

Person         = Name + BirthDate + Gender;

Name           = text;

BirthDate   = Date;

Gender       = enum (Male, Female);

Date            = text;

text             = predefined;


Figure 1: Domain definitions of the Family

Based on these domain definitions the metaprocessor generates the following skeleton Elisa source code (Figure 2).


<< BEGIN OF INPUT 
Family = Father + Mother + Children;
Father = Person;
Mother = Person;
Children = collection(Person);
Person = Name + BirthDate + Gender;
Name = text;
BirthDate = Date;
Gender = enum(Male, Female);
Date = text;
text = predefined;
END OF INPUT >> 

component Familys; 
 type Family; 
      newFamily(Father, Mother, Children) -> Family; 
      getFather(Family) -> Father; 
      getMother(Family) -> Mother; 
      getChildren(Family) -> Children; 
      setFather(Family, Father) -> nothing; 
      setMother(Family, Mother) -> nothing; 
      setChildren(Family, Children) -> nothing; 
begin
      newFamily(Father, Mother, Children) = Family:[Father; Mother; Children]; 
      getFather(aFamily) = aFamily.Father; 
      getMother(aFamily) = aFamily.Mother; 
      getChildren(aFamily) = aFamily.Children; 
      setFather(aFamily, aFather) = [ aFamily.Father:= aFather];
      setMother(aFamily, aMother) = [ aFamily.Mother:= aMother];
      setChildren(aFamily, aChildren) = [ aFamily.Children:= aChildren];
end component Familys; 

type Father = Person; 

type Mother = Person; 

type Children = list(Person); 

component Persons; 
 type Person; 
      newPerson(Name, BirthDate, Gender) -> Person; 
      getName(Person) -> Name; 
      getBirthDate(Person) -> BirthDate; 
      getGender(Person) -> Gender; 
      setName(Person, Name) -> nothing; 
      setBirthDate(Person, BirthDate) -> nothing; 
      setGender(Person, Gender) -> nothing; 
begin
      newPerson(Name, BirthDate, Gender) = Person:[Name; BirthDate; Gender]; 
      getName(aPerson) = aPerson.Name; 
      getBirthDate(aPerson) = aPerson.BirthDate; 
      getGender(aPerson) = aPerson.Gender; 
      setName(aPerson, aName) = [ aPerson.Name:= aName];
      setBirthDate(aPerson, aBirthDate) = [ aPerson.BirthDate:= aBirthDate];
      setGender(aPerson, aGender) = [ aPerson.Gender:= aGender];
end component Persons; 

type Name = text; 

type BirthDate = Date; 

type Gender = (Male, Female); 

type Date = text; 


Figure 2: Skeleton of the Family

 The metaprocessor generates, depending on its input a number of Elisa components and type declarations.

In Elisa, a software component is a self-contained building block.  It has a well-defined interface with its outside world. A software component is designed to perform a number of related functions. It consists of two parts:

1. The interface-section. It contains the signatures of the operations and functions that may be called from outside the component. Additionally, it may also contain type-specifications.

2. The implementation-section. It contains the definitions of the operations and functions that are externally accessible as specified in the interface-section. It may also contain other definitions that are local to the component.

The metaprocessor generates three kinds of functions: the new functions create new so-called descriptors. A descriptor is a data structure that describes a certain type. For example, the newFamily function generates a new family descriptor. The newPerson function creates a new Person descriptor. A get function retrieves an element of the specified descriptor, and a set function changes an element of the specified descriptor.

6. Dialogue Sessions

Based on the skeleton program we are able to set-up a dialogue session with the system. In our case this will be a dialogue with the Elisa Development System. Because we start with an “empty” program we need first to feed the system with some information about a specific application. In following steps we may use this information in dialogues with the system. To demonstrate these steps we will return so our Family application.  Because the skeleton program is still very general we need to feed it with data about a specific family. (Figure 3 ).  


include “Family.txt”;

father = newPerson(“John”, “04-10-1965”, Male);

mother = newPerson(“Liza”, “08-05-1968”, Female);

child1 = newPerson(“Ann” , “20-07-1994”, Female);

child2 = newPerson(“Peter”,”15-03-1998”, Male);

children = {child1, child2};

family1 = newFamily(father, mother, children);  


Figure 3:  Specific Family Data

The first line of the session indicates that the skeleton program as generated by the metaprocessor should be included in the program.

   The following lines contain calls of  functions that are defined in the skeleton program (see Figure 2). For example, newPerson and newFamily are defined in the skeleton program. Curly brackets { } are used to collect elements in a list.

   After feeding the system with some basic information about a Family we can now ask the system what it knows about the family by querying the system with: family1?    

   The answer is shown in Figure 4. The result is a Family-tree showing the structure of the tree and its contents.  


include "Family14.txt";
father = newPerson("John", "04-10-1965", Male);
mother = newPerson("Liza", "08-05-1968", Female);
child1 = newPerson("Ann" , "20-07-1994", Female);
child2 = newPerson("Peter","15-03-1998", Male); 
children = {child1, child2};
Fam1 = newFamily(father, mother,children);
Fam1? 
Family:[Father = Person:[Name = "John";
                         BirthDate = "04-10-1965";
                         Sex = Male];
        Mother = Person:[Name = "Liza";
                         BirthDate = "08-05-1968";
                         Sex = Female];
        Children = { Person:[Name = "Ann";
                             BirthDate = "20-07-1994";
                             Sex = Female], 
                     Person:[Name = "Peter";
                             BirthDate = "15-03-1998";
                             Sex = Male]}]

Figure 4: Querying the system with: family1?

Based on this information the user can now answer questions like: Are the data structures right? Are the values right? This exercise shows how the system gives formatted output based on the information gathered by the metaprocessor, the compiler, and the run-time system. This facility provides high-level debugging and verification support and is of great help in the testing and maintenance phases. 

7.  A program about concentric circles

Our next example is: how to define a collection of concentric circles. We know from mathematics that the key concepts of concentric circles are circles with a common center point and with variable radiuses. We use those key concepts in our domain definitions (Figure 5).


<< Concentric Circles Version 1 >>

 

Circle = Center + Radius;

Center = Point;

Point = X + Y;

X = Number; Y = Number;

Radius = Number;

Number = integer;

integer = predefined;

ConcentricCircles = collection (Circle);


Figure 5: Domain definitions of Concentric Circles

  These domain definitions will be processed by the metaprocessor. The result is a skeleton file, called "ConcCirclesV1.txt". A session showing  the data of  3 concentric circles is shown in  Figure 6.


include "ConcCirclesV1.txt";

ConcCircles(Center, Number) -> multi(Circle);
ConcCircles(center, n) = newCircle(center, 1 .. n);

center = newPoint(1,1);
{ConcCircles(center, 3)}?

{ Circle:[Center = Point:[X = 1;
                          Y = 1];
          Radius = 1], 
  Circle:[Center = Point:[X = 1;
                          Y = 1];
          Radius = 2], 
  Circle:[Center = Point:[X = 1;
                          Y = 1];
          Radius = 3]}


Figure 6: Session of 3 concentric circles

  In order to understand this example we first have to explain the following function:

ConcCircles(Center, Number) -> multi(Circle);

ConcCircles(center, n) = newCircle(center, 1 .. n);

The first line specifies the signature of the function. A signature specifies the types of the input values and the type of the  output values. Types are often derived from the domain names. In our example the input types and output type are the same as the corresponding domain names. The output specification multi(Circle) states that the function represents a number of Circles. One call of this function may generate a multitude of Circle-descriptors.

The second line defines the operations of the function. The expression 1 .. n is a multi-value expression. Its evaluation will result in the generation of the successive values 1, 2, …n.  The calling procedure of a single value is different from a multi-value expression. A call of a single value function delivers (at most) one value and returns control. A call of a multi-value function delivers multiple values, one by one, as many as needed by the calling program or as long as the called program allows.

8.  Domain substitution applied to concentric circles

Our next example illustrates domain substitution as discussed in “4.1 Substitution of Domain Definitions”.  As a starting point we use the domain definitions of the preceding example and we substitute the Center point by its coordinates X and Y. The result is a reduced set of domain definitions (Figure 7).


<< Concentric Circles Version 2 >>

Circle = X + Y + Radius;

X = Number; Y = Number;

Radius = Number;

Number = integer;

integer = predefined;

ConcentricCircles = collection (Circle);


Figure 7: Domain substitution applied to Concentric Circles

These domain definitions will be input for the metaprocessor. The result is a skeleton file, called "ConcCirclesV2.txt". A session shows  the data of  3 concentric circles based on Center point substitution (Figure 8).


include "ConcCirclesV2.txt";

 

ConcCircles(X, Y, Number) -> multi(Circle);

ConcCircles(x, y, n) = newCircle(x, y, 1 .. n);

 

{ConcCircles(1, 1, 3)}?

 

{ Circle:[X = 1;

          Y = 1;

          Radius = 1],

  Circle:[X = 1;

          Y = 1;

          Radius = 2],

  Circle:[X = 1;

          Y = 1;

          Radius = 3]}  


Figure 8: Example of domain substitution of concentric circles 

9.  An Order Processing Application 

We will now demonstrate more sophisticated capabilities of metaprogramming. Therefore we will develop a mini-application using database modeling. Let us use, as an example, the operations of a bookshop. A bookshop has customers that are ordering books, and suppliers, which are sending books to a bookshop after purchase orders have been received. Thus, the key concepts of a bookshop are: customers, orders, articles, invoices, purchase orders, suppliers.


 

<< Order Processing Application  >>

 

Customer          = Name + Address;

Order                = Customer + Article + Quantity;

Article               = Description + Code;

Invoice               = Order + Amount;

PurchaseOrder = Supplier + Article + Quantity;

Supplier             = Name + Address;

Supply                = Supplier + Article + Price + Quantity;

Inventory           = Article + Supplier + Price + Quantity;

 

Database = Customerset + Articleset +  Orderset

                    + Inventoryset + Invoiceset +  PurhseOrderset;

Articleset                 = collection (Article);

Customerset            = collection (Customer);

Orderset                  = collection (Order);

Inventoryset            = collection (Inventory);

Invoiceset                = collection (Invoice);

PurchaseOrderset  = collection (PurchaseOrder);

 

Name            = text;

Address        = text;

Quantity      = integer;

Description  = text;

Amount        = real;

Price             = real;

Code             = integer;

integer          = predefined;

real               = predefined;

text                = predefined;  


Figure 9:  Domain definitions for an Order Processing Application

We start with a set of domain definitions based on these key concepts. In addition, also a database is defined.. See Figure 9. These domain definitions will be input for the metaprocessor. The result is a skeleton file, called "OrderProcessing.txt". Based on this skeleton information it is now possible to set up an initial database and to introduce a first Customer with a first Order. Let us further assume that the same Customer decides to place a second Order for the same Article (Figure 10).


include "OrderProcessing.txt";

 

db = newDatabase( alist(Customer),

                  alist(Article),

                  alist(Order),

                  alist(Inventory),

                  alist(Invoice),

                  alist(PurchaseOrder));

 

Cust1 = newCustomer("Alex", "Addr1");

add(Cust1, getCustomerset(db));

 

Art1 = newArticle("Pencil", 123);

add(Art1, getArticleset(db));

 

Order1 = newOrder(Cust1, Art1, 15);

add(Order1, getOrderset(db));

 

Order2 = newOrder(Cust1, Art1, 30);

add(Order2, getOrderset(db));  


Figure 10: Example of Initializing the Order Processing Application

In this session the following functions are defined by the skeleton program: newDatabase, newCustomer, getCustomerset,  newArticle, getArticleset, newOrder, getOrderset. The alist and the add functions are built-in Elisa functions. A session shows the data after the initialization phase.  (Figure 11).


db?
Database:[Customerset = { Customer:[Name = "Alex";
                                    Address = "Addr1"]};
          Articleset = { Article:[Description = "Pencil";
                                  Code = 123]};
          Orderset = { Order:[Customer = Customer:[Name = "Alex";
                                                   Address = "Addr1"];
                              Article = Article:[Description = "Pencil";
                                                 Code = 123];
                              Quantity = 30], 
                       Order:[Customer = Customer:[Name = "Alex";
                                                   Address = "Addr1"];
                              Article = Article:[Description = "Pencil";
                                                 Code = 123];
                              Quantity = 15]};
          Inventoryset = { };
          Invoiceset = { };
          PurchaseOrderset = { }]

Figure 11: Data after the initialization of Figure 10.

 Let us further assume that the database manager wants to inspect all the orders in the database. He uses therefore the following expression:

items(getOrderset(db))?

  This expression uses the built-in Elisa function items. This function is a multi-value function that will return all the elements of a list. In this example it will  return all the Orders in the Orderset. For the time being there are only two orders in the database. (Figure 12).


items(getOrderset(db))?
Order:[Customer = Customer:[Name = "Alex";
                            Address = "Addr1"];
       Article = Article:[Description = "Pencil";
                          Code = 123];
       Quantity = 30]
Order:[Customer = Customer:[Name = "Alex";
                            Address = "Addr1"];
       Article = Article:[Description = "Pencil";
                          Code = 123];
       Quantity = 15]

Figure 12: Example of the result of a query based on the input of Figure 11.

  10.  Airport Information System

  As another example of an application we define a simple airport information system. Discovering the key concepts of an airport is rather simple: the task of an airport is to manage incoming and outgoing flights. Consequently, the key concept is: flight. To characterize a flight we need a flight number, the origin and destination of a flight, the arrival and departure times, the gate number and possible delays. Not all information should be available at once. We know from experience that flight information may change every moment. To describe domain definitions for flights it is necessary that information can be changed. Therefore we will discuss update operations. However, first we need to define the domain definitions for flights (Figure 13).  


<< Airport Information System >>

 

Flight = Flightno + Origin + Destination + Arrivaltime + Departuretime + Delay + Gate;

 

Flightno             = text;

Origin                = Airport;

Destination        = Airport;

Arrivaltime        = Time;

Departuretime   = Time;

Delay                  = Time;

 

Airport              = text;

Time                  = Hour + Minutes;

Hour                  = integer;

Minutes             = integer;

Gate                   = text;

Flightlist            = collection (Flight);

 

text               = predefined;

integer         = predefined;


Figure 13: Domain definitions of an Airport Information System

These domain definitions will be input for the metaprocessor. The result is a skeleton file, called "Airport.txt". Based on this skeleton information it is now possible to specify a number of flights (Figure 14).


			     << Airport >>
include "Airport12.txt";

time(Hour, Minutes) -> Time;
time(H, M) = newTime(H, M);

FlightList = alist(Flight);

flight1 = newFlight ("KL 677","Amsterdam","Calgary", time(07, 40), time(10,50), time(0, 0), "Gate A" );
add(FlightList, flight1);
flight2 = newFlight ("AF345","Paris","Denver", time(08, 15), time(11, 10), time(0, 0), "Gate B" );
add(FlightList, flight2);

setDelay(flight2,time(2, 30));
setDeparturetime(flight2,time(13, 30));

FlightList?
{ Flight:[Flightno = "KL 677";
          Origin = "Amsterdam";
          Destination = "Calgary";
          Arrivaltime = Time:[Hour = 7;
                              Minutes = 40];
          Departuretime = Time:[Hour = 10;
                                Minutes = 50];
          Delay = Time:[Hour = 0;
                        Minutes = 0];
          Gate = "Gate A"], 
  Flight:[Flightno = "AF345";
          Origin = "Paris";
          Destination = "Denver";
          Arrivaltime = Time:[Hour = 8;
                              Minutes = 15];
          Departuretime = Time:[Hour = 13;
                                Minutes = 30];
          Delay = Time:[Hour = 2;
                        Minutes = 30];
          Gate = "Gate B"]}

Figure 14: Session of the Airport Information System

The session of the Airport Information System shows some new elements. After the include of the skeleton file, a time function is defined  to simplify time notations. Two flights are introduced. Both are added to the FlightList. It appears that the second flight is delayed. This will be expressed by the setDelay function as defined in the skeleton file. Accordingly, the time of departure is also updated. The effect of both operations is made visible by a query of FlightList?

11.     A Rental Boat Business

In the preceding examples we discussed homogeneous lists where all the elements are of the same type. In this section we will discuss the relations between alternative domain definitions and heterogeneous lists. We use as an example a Rental Boat Business.  Let us assume that we want to describe a small start-up company that rents small boats. The company has 4 rowboats, 3 motorboats, and 2 sailboats. With this kind of information we are already able to create a set of related domain definitions because we know the key concepts of the business. See Figure 15.


  <<  Alternative Domain Definitions  >> 

  <<       of a Rental Boat Business       >>

 

Boat = Sailboat | Rowboat | Motorboat;

Rowboat = ID + Status + Persons + Rent;

Motorboat = ID + Status + Persons + Rent + Speed;

Sailboat = ID + Status + Persons + Rent + Size;

Boatset = collection (Boat);

 

ID = text;

Status = enum ( Free, Reserved, Occupied);

Persons = integer;

Rent = real;

Size = integer;

Speed = real;

integer = predefined;

real  = predefined;

text = predefined;  


Figure 15: Domain definitions of a Rental Boat Business

Mark that we did not include in our domain definitions the numbers of the boats. That will be done later. In general, values are not included in domain definitions. They belong to the following phase.

    Every boat has a unique identification (ID). The Status domain is an enumeration domain reflecting the status of the boat. The Persons domain specifies the maximum of allowed persons in the boat when the boat is Free and it specifies the actual number of persons when the boat is Occupied. The Rent domain specifies the amount of rent to be paid for one hour of sailing.

    Based on these domain definitions the metaprocessor will generate a skeleton file. If we compare the number of domain definitions in the meta input file (14) with the number of generated lines in the skeleton file (130), we get an expansion factor of almost 10. A complete listing of the skeleton file is given in Appendix A. Because of the size of the skeleton file we will discuss only some parts of the contents of this file. First, we will discuss the three compound domain definitions. Secondly, the alternative domain definition will be discussed.

     The domain definitions for Sailboat, Motorboat, and Rowboat are quit similar in nature. That means that the corresponding components are also similar. Therefore we will discuss only one of the three compound domain definitions in detail, namely Sailboat. The corresponding component is described in Figure 16.  


component Sailboats; 
 type Sailboat; 
      newSailboat(ID, Status, Persons, Rent, Size) -> Sailboat; 
      getID(Sailboat) -> ID; 
      getStatus(Sailboat) -> Status; 
      getPersons(Sailboat) -> Persons; 
      getRent(Sailboat) -> Rent; 
      getSize(Sailboat) -> Size; 
      setID(Sailboat, ID) -> nothing; 
      setStatus(Sailboat, Status) -> nothing; 
      setPersons(Sailboat, Persons) -> nothing; 
      setRent(Sailboat, Rent) -> nothing; 
      setSize(Sailboat, Size) -> nothing; 
begin
      newSailboat(ID, Status, Persons, Rent, Size) = Sailboat:[ID; Status; Persons; Rent; Size]; 
      getID(aSailboat) = aSailboat.ID; 
      getStatus(aSailboat) = aSailboat.Status; 
      getPersons(aSailboat) = aSailboat.Persons; 
      getRent(aSailboat) = aSailboat.Rent; 
      getSize(aSailboat) = aSailboat.Size; 
      setID(aSailboat, aID) = [ aSailboat.ID:= aID];
      setStatus(aSailboat, aStatus) = [ aSailboat.Status:= aStatus];
      setPersons(aSailboat, aPersons) = [ aSailboat.Persons:= aPersons];
      setRent(aSailboat, aRent) = [ aSailboat.Rent:= aRent];
      setSize(aSailboat, aSize) = [ aSailboat.Size:= aSize];
end component Sailboats; 

Figure 16: Example of a compound domain component

 As explained earlier, the metaprocessor generates three kinds of functions for compound domains: the new functions, the get functions, and the set functions. The new functions create new descriptors. A descriptor is a data structure that describes a certain type. For example, the newSailboat function generates a new Sailboat descriptor. A get functions retrieves an element of the specified descriptor, and a set function changes an element of the descriptor.

For alternative domain definitions the generated skeleton file contains a special component to handle alternative domains. In our example it is the component Boats. A stripped version is shown in Figure 17. This component introduces (line 2) the category Boat with the members Sailboat, Rowboat, and Motorboat.  In Elisa, categories are used to specify alternative domain types. The following lines of the interface-section (line 3, etc) specify the signatures of the functions defined for the Boat category.  In the implementation-section the corresponding functions are defined. Let us use as an example the getID operation. In the interface-section the one-line signature specifies as input an item of the type Boat. In the implementation-section there are 3 definition lines for getID. Each line tests if the incoming descriptor is one of the category members.  If so, the corresponding function will be executed. For example, the first line of the implementation-section test if the incoming Boat-descriptor is Sailboat-descriptor.  If that is the case, the getID function of the  Sailboats component will be evaluated and the ID value of the Sailboat will be returned. The same procedure applies to other functions and members of the category.  


component Boats; 
 type Boat = category (Sailboat, Rowboat, Motorboat); 
      getID(Boat) -> ID; 
      getStatus(Boat) -> Status; 
      getPersons(Boat) -> Persons; 
      getRent(Boat) -> Rent; 
      setID(Boat, ID) -> nothing; 
      setStatus(Boat, Status) -> nothing; 
      setPersons(Boat, Persons) -> nothing; 
      setRent(Boat, Rent) -> nothing; 
begin
      getID(Sailboat:aSailboat) = getID(aSailboat); 
      getID(Rowboat:aRowboat) = getID(aRowboat); 
      getID(Motorboat:aMotorboat) = getID(aMotorboat); 
      getStatus(Sailboat:aSailboat) = getStatus(aSailboat); 
      getStatus(Rowboat:aRowboat) = getStatus(aRowboat); 
      getStatus(Motorboat:aMotorboat) = getStatus(aMotorboat); 
      getPersons(Sailboat:aSailboat) = getPersons(aSailboat); 
      getPersons(Rowboat:aRowboat) = getPersons(aRowboat); 
      getPersons(Motorboat:aMotorboat) = getPersons(aMotorboat); 
      getRent(Sailboat:aSailboat) = getRent(aSailboat); 
      getRent(Rowboat:aRowboat) = getRent(aRowboat); 
      getRent(Motorboat:aMotorboat) = getRent(aMotorboat); 
      setID(Sailboat:aSailboat, aID) = setID(aSailboat, aID); 
      setID(Rowboat:aRowboat, aID) = setID(aRowboat, aID); 
      setID(Motorboat:aMotorboat, aID) = setID(aMotorboat, aID); 
      setStatus(Sailboat:aSailboat, aStatus) = setStatus(aSailboat, aStatus); 
      setStatus(Rowboat:aRowboat, aStatus) = setStatus(aRowboat, aStatus); 
      setStatus(Motorboat:aMotorboat, aStatus) = setStatus(aMotorboat, aStatus); 
      setPersons(Sailboat:aSailboat, aPersons) = setPersons(aSailboat, aPersons); 
      setPersons(Rowboat:aRowboat, aPersons) = setPersons(aRowboat, aPersons); 
      setPersons(Motorboat:aMotorboat, aPersons) = setPersons(aMotorboat, aPersons); 
      setRent(Sailboat:aSailboat, aRent) = setRent(aSailboat, aRent); 
      setRent(Rowboat:aRowboat, aRent) = setRent(aRowboat, aRent); 
      setRent(Motorboat:aMotorboat, aRent) = setRent(aMotorboat, aRent); 
end component Boats; 

Figure 17: Example of a category component

  The skeleton file can now be used as basis for writing programs. We return to our rental boat business. Remember that we want to describe a start-up company that rents small boats. The company has 4 rowboats, 3 motorboats, and 2 sailboats.  First, we need to define those boats. (Figure 18).


include "BoatRental12.txt";

Rbt01  = newRowboat("RB01", Occupied, 2, 10.);
Rbt02  = newRowboat("RB02", Occupied, 2, 10.);
Rbt03  = newRowboat("RB03", Free, 4, 15.);
Rbt04  = newRowboat("RB04", Occupied, 4, 15.);

Mbt01  = newMotorboat("MB01", Occupied, 6, 20., 25.);
Mbt02  = newMotorboat("MB02", Occupied , 6, 20., 25.);
Mbt03  = newMotorboat("MB03", Free, 6, 30., 25.);

Sbt01  = newSailboat("SB01", Occupied, 6, 40., 4);
Sbt02  = newSailboat("SB02", Free, 6, 50., 4);

AllBoats = {Boat: Rbt01, Rbt02, Rbt03, Rbt04, Mbt01, Mbt02, Mbt03, Sbt01, Sbt02);

Figure 18: Heterogeneous list of Boats

All the boats of the company are defined, including their status. The boats are collected in the AllBoats list. Mark that this is a heterogeneous list, containing descriptors of different types all belonging to the category Boat. Let us assume the following scenario: at a certain moment in time the manager of the company  wants an overview of the free boats. He uses in the following session (Figure 18) the AllFreeBoats procedure. This procedure operates on all elements belonging to the Boat category. The result is a series of free boats.  


AllFreeBoats(list(Boat)) -> multi(Boat);
AllFreeBoats(boats) =
 [ aBoat = items(boats);
   if getStatus(aBoat) == Free then aBoat;
 ];

AllFreeBoats(AllBoats)?
Rowboat:[ID = "RB03";
         Status = Free;
         Persons = 4;
         Rent = 15.]
Motorboat:[ID = "MB03";
           Status = Free;
           Persons = 6;
           Rent = 30.;
           Speed = 25.]
Sailboat:[ID = "SB02";
          Status = Free;
          Persons = 6;
          Rent = 50.;
          Size = 4]

Figure 19: Heterogeneous series of free Boats

In the mean time a potential customer comes with a special request. He wants to rent the cheapest boat there is for 4 persons. The rent may not exceed 20 dollars. The manager returns to his computer and uses the following procedure (Figure 20).  


AllCheapestBoats(list(Boat), Persons, Rent) -> multi(Boat);
AllCheapestBoats(boats, persons, rent) = 
 [ aBoat = items(boats);
   if getStatus(aBoat) == Free &
      getPersons(aBoat) >= persons &
      getRent(aBoat) <= rent 
   then aBoat;
 ];

AllCheapestBoats(AllBoats, 4, 20.)?
Rowboat:[ID = "RB03";
         Status = Free;
         Persons = 4;
         Rent = 15.]

Figure 20: Selection of free Boats

  The result is that only one rowboat fulfills the requirements.   Also this procedure operates on all elements belonging to the Boat category. That means that, for example, the getStatus operation should be able to activate the getStatus operations of Rowboat, Motorboat, or Sailboat, depending on the actual descriptor type.

 

12.  Benefits of Domain Definitions?

 

The question we have to answer is: What are the benefits of using domain definitions? Here are some answers:

 

·         Domain definitions can be applied to system modeling as well as to implementations. In both cases domain definitions can be used to describe the key concepts of the problem area.

 

·         Domain definitions are high-level means of communications, not only for the developers but also for system analysts, system designers, users, and customers.

 

·         Using domain definitions requires focusing on the key concepts of the problem to be solved. They facilitate a top-down approach.

 

·         Domain definitions have a number of interesting properties: Domain definitions are concise. They are easy to understand and to derive. They are declarative in nature. Imperative programming steps are excluded. The order of domain definitions is irrelevant. The syntax is minimal. There is only one rule: every domain name used on the right side of a definition should also be defined on the left side.

 

·         The translation of domain definitions to the skeleton output is fast and error free, assuming that domain definitions are consistent and complete. Both aspects are checked by the metaprocessor.

 

·         Discovering the relevant domain definitions begins with the decomposition of top-level domain definitions. It has a number of advantages. It starts top down with high-level problem oriented concepts, decomposing them into smaller definitions until the predefined domains are found. The decomposition process requires often choices that have their impact in the implementation phase.

 

·         Alternative designs can easily be expressed by changing some domain definitions.

 

·         Domain definitions can be used to make run-time data visible.  The information provided by the domain definitions together with information collected by the compiler and the run-time system enables the system to output meaningful data structures related to the domain definitions. These facilities provide high-level debugging and verification support and are of great help in the testing and maintenance phases.

 

15.  Future Work

 

It will be clear that the combination of domain definitions and metaprogramming also could be applied to other languages, such as C, C++, Java, etc. However, it is not obvious from the beginning that a smooth transition from domain definitions to meaningful data structures will fit into the programming model of those languages.  That should be an area of investigation.

Another area of investigation is the output of the current metaprocessor. In many applications a number of the generated functions are not used.  Can the superfluous functions be removed from the final program by means of an optimization tool?

Another question is: what sorts of applications are suitable for this approach and what sorts are not?

 

16.    Implementation

 

The Elisa language and the principles of domain orientation are described in “Elisa and Domain Orientation”[13].  The Elisa Development System is available for Window computers. The system can be downloaded as described at the website[13]. The system consists of the metaprocessor, a compiler, a linker and a run-time environment.

 

17. Related Work

 

Metaprogramming is supported across many languages using many different techniques. Here’s a brief list of some popular languages that support metaprogramming in some form [ 1 –12]: Lisp, C**, Ruby, Haskell (Template), C#.

    However, to the knowledge of the author none of them is using domain definitions as input.

 

References

[1]  On Lisp Macros: http://dunsmor.com/lisp/onlisp/onlisp_11.html

[2]   Metaprogramming Tutorial: Ocaml and Template Haskell: https://nicolaspouillard.fr/talks/cufp-metaprogramming-tutorial-slides.pdf

[3]   "The Boost Metaprogramming Library (Boost MPL)". http://www.boost.org/doc/libs/1_57_0/libs/mpl/doc/

[4]   Veldhuizen, Todd (May 1995). "Using C++ template metaprograms". C++ Report 7 (4): 36–43. http://web.archive.org/web/20090304154029/http://ubiety.uwaterloo.ca/~tveldhui/papers/Template-Metaprograms/meta-art.html

[5]  "Template Haskell". (type-safe metaprogramming in Haskell)  https://wiki.haskell.org/Template_Haskell

[6]   Bright, Walter. "Templates Revisited". (template metaprogramming in the D programming language). http://dlang.org/templates-revisited.html

[7]  Koskinen, Johannes. "Metaprogramming in C++". http://staff.ustc.edu.cn/~xyfeng/teaching/FOPL/lectureNotes/MetaprogrammingCpp.pdf

[8]  Attardi, Giuseppe; Cisternino, Antonio. "Reflection support by means of template metaprogramming".  http://lcgapp.cern.ch/project/architecture/ReflectionPaper.pdf

[9]  Amjad, Zeeshan. "Template Meta Programming and Number Theory". http://www.codeproject.com/Articles/19989/Template-Meta-Programming-and-Number-Theory

[10] Amjad, Zeeshan. "Template Meta Programming and Number Theory: Part 2". http://www.codeproject.com/Articles/20180/Template-Meta-Programming-and-Number-Theory-Part

[11]  "A library for LISP-style programming in C++". http://www.intelib.org/intro.html

[12] Sebastian Günther, Marco Fischer. Metaprogramming in Ruby: a pattern catalog. PLOP ’10 Proceedings of the 17th Conference on Pattern Languages of Program

[13] Klunder, Jan. “Elisa & Domain Orientation”. http://jklunder.home.xs4all.nl/

[14] Klunder, Jan. “Language Description of Elisa”. http://jklunder.home.xs4all.nl/elisa/part01/doc000.html

[15] Klunder, Jan. “Highlights of Elisa”. http://jklunder.home.xs4all.nl/elisa/part00/Highlights%20of%20Elisa.html

 


 

 

 

Appendix:   Skeleton file of Rental Boat Company

 

<<   BEGIN OF INPUT

Boat = Sailboat | Rowboat | Motorboat;

Rowboat = ID + Status + Persons + Rent;

Motorboat = ID + Status + Persons + Rent + Speed;

Sailboat = ID + Status + Persons + Rent + Size;

Boatset = collection(Boat);

ID = text;

Status = enum(Free, Reserved, Occupied);

Persons = integer;

Rent = real;

Size = integer;

Speed = real;

integer = predefined;

real = predefined;

text = predefined;

    END OF INPUT  >>

 

component Boats;

 type Boat = category (Sailboat, Rowboat, Motorboat);

      getID(Boat) -> ID;

      getStatus(Boat) -> Status;

      getPersons(Boat) -> Persons;

      getRent(Boat) -> Rent;

      setID(Boat, ID) -> nothing;

      setStatus(Boat, Status) -> nothing;

      setPersons(Boat, Persons) -> nothing;

      setRent(Boat, Rent) -> nothing;

begin

      getID(Sailboat:aSailboat) = getID(aSailboat);

      getID(Rowboat:aRowboat) = getID(aRowboat);

      getID(Motorboat:aMotorboat) = getID(aMotorboat);

      getStatus(Sailboat:aSailboat) = getStatus(aSailboat);

      getStatus(Rowboat:aRowboat) = getStatus(aRowboat);

      getStatus(Motorboat:aMotorboat) = getStatus(aMotorboat);

      getPersons(Sailboat:aSailboat) = getPersons(aSailboat);

      getPersons(Rowboat:aRowboat) = getPersons(aRowboat);

      getPersons(Motorboat:aMotorboat) = getPersons(aMotorboat);

      getRent(Sailboat:aSailboat) = getRent(aSailboat);

      getRent(Rowboat:aRowboat) = getRent(aRowboat);

      getRent(Motorboat:aMotorboat) = getRent(aMotorboat);

      setID(Sailboat:aSailboat, aID) = setID(aSailboat, aID);

      setID(Rowboat:aRowboat, aID) = setID(aRowboat, aID);

      setID(Motorboat:aMotorboat, aID) = setID(aMotorboat, aID);

      setStatus(Sailboat:aSailboat, aStatus) = setStatus(aSailboat, aStatus);

      setStatus(Rowboat:aRowboat, aStatus) = setStatus(aRowboat, aStatus);

      setStatus(Motorboat:aMotorboat, aStatus) = setStatus(aMotorboat, aStatus);

      setPersons(Sailboat:aSailboat, aPersons) = setPersons(aSailboat, aPersons);

      setPersons(Rowboat:aRowboat, aPersons) = setPersons(aRowboat, aPersons);

      setPersons(Motorboat:aMotorboat, aPersons) = setPersons(aMotorboat, aPersons);

      setRent(Sailboat:aSailboat, aRent) = setRent(aSailboat, aRent);

      setRent(Rowboat:aRowboat, aRent) = setRent(aRowboat, aRent);

      setRent(Motorboat:aMotorboat, aRent) = setRent(aMotorboat, aRent);

end component Boats;

 

component Rowboats;

 type Rowboat;

      newRowboat(ID, Status, Persons, Rent) -> Rowboat;

      getID(Rowboat) -> ID;

      getStatus(Rowboat) -> Status;

      getPersons(Rowboat) -> Persons;

      getRent(Rowboat) -> Rent;

      setID(Rowboat, ID) -> nothing;

      setStatus(Rowboat, Status) -> nothing;

      setPersons(Rowboat, Persons) -> nothing;

      setRent(Rowboat, Rent) -> nothing;

begin

      newRowboat(ID, Status, Persons, Rent) = Rowboat:[ID; Status; Persons; Rent];

      getID(aRowboat) = aRowboat.ID;

      getStatus(aRowboat) = aRowboat.Status;

      getPersons(aRowboat) = aRowboat.Persons;

      getRent(aRowboat) = aRowboat.Rent;

      setID(aRowboat, aID) = [ aRowboat.ID:= aID];

      setStatus(aRowboat, aStatus) = [ aRowboat.Status:= aStatus];

      setPersons(aRowboat, aPersons) = [ aRowboat.Persons:= aPersons];

      setRent(aRowboat, aRent) = [ aRowboat.Rent:= aRent];

end component Rowboats;

 

component Motorboats;

 type Motorboat;

      newMotorboat(ID, Status, Persons, Rent, Speed) -> Motorboat;

      getID(Motorboat) -> ID;

      getStatus(Motorboat) -> Status;

      getPersons(Motorboat) -> Persons;

      getRent(Motorboat) -> Rent;

      getSpeed(Motorboat) -> Speed;

      setID(Motorboat, ID) -> nothing;

      setStatus(Motorboat, Status) -> nothing;

      setPersons(Motorboat, Persons) -> nothing;

      setRent(Motorboat, Rent) -> nothing;

      setSpeed(Motorboat, Speed) -> nothing;

begin

      newMotorboat(ID, Status, Persons, Rent, Speed) = Motorboat:[ID; Status; Persons; Rent; Speed];

      getID(aMotorboat) = aMotorboat.ID;

      getStatus(aMotorboat) = aMotorboat.Status;

      getPersons(aMotorboat) = aMotorboat.Persons;

      getRent(aMotorboat) = aMotorboat.Rent;

      getSpeed(aMotorboat) = aMotorboat.Speed;

      setID(aMotorboat, aID) = [ aMotorboat.ID:= aID];

      setStatus(aMotorboat, aStatus) = [ aMotorboat.Status:= aStatus];

      setPersons(aMotorboat, aPersons) = [ aMotorboat.Persons:= aPersons];

      setRent(aMotorboat, aRent) = [ aMotorboat.Rent:= aRent];

      setSpeed(aMotorboat, aSpeed) = [ aMotorboat.Speed:= aSpeed];

end component Motorboats;

 

component Sailboats;

 type Sailboat;

      newSailboat(ID, Status, Persons, Rent, Size) -> Sailboat;

      getID(Sailboat) -> ID;

      getStatus(Sailboat) -> Status;

      getPersons(Sailboat) -> Persons;

      getRent(Sailboat) -> Rent;

      getSize(Sailboat) -> Size;

      setID(Sailboat, ID) -> nothing;

      setStatus(Sailboat, Status) -> nothing;

      setPersons(Sailboat, Persons) -> nothing;

      setRent(Sailboat, Rent) -> nothing;

      setSize(Sailboat, Size) -> nothing;

begin

      newSailboat(ID, Status, Persons, Rent, Size) = Sailboat:[ID; Status; Persons; Rent; Size];

      getID(aSailboat) = aSailboat.ID;

      getStatus(aSailboat) = aSailboat.Status;

      getPersons(aSailboat) = aSailboat.Persons;

      getRent(aSailboat) = aSailboat.Rent;

      getSize(aSailboat) = aSailboat.Size;

      setID(aSailboat, aID) = [ aSailboat.ID:= aID];

      setStatus(aSailboat, aStatus) = [ aSailboat.Status:= aStatus];

      setPersons(aSailboat, aPersons) = [ aSailboat.Persons:= aPersons];

      setRent(aSailboat, aRent) = [ aSailboat.Rent:= aRent];

      setSize(aSailboat, aSize) = [ aSailboat.Size:= aSize];

end component Sailboats;

 

 type Boatset = list(Boat);

 

 type ID = text;

 

 type Status = (Free, Reserved, Occupied);

 

 type Persons = integer;

 

 type Rent = real;

 

 type Size = integer;

 

 type Speed = real;

 

 

 

 

 

 

 

 

1.1 Classification of Models

Models might be classified in many ways. We will describe four kinds of subdivisions:

Physical or Abstract. First, models can be distinguished as being either physical models or abstract models.

Physical models are the most easily understood. They are usually physical replicas, often on a reduced scale, of objects under study. Static physical models, such as architectural models, help us to visualize floor plans and space relationships. Dynamic physical models are used as in wind tunnels to show the aero-dynamic characteristics of proposed aircraft design.

Abstract models are based on symbols, rather than physical devices. The abstract model is much more common than the physical model but is less often recognized for what it is. A mental image, a verbal description, a drawing, or a mathematical formula can represent an abstract model of a system. Models used for designing software systems are abstract models.

Descriptive or Prescriptive. Models can also be classified as being either descriptive models or prescriptive models.

Descriptive models are describing existing systems. They are used for studying specific characteristics of the real system. Examples are models for weather prediction, economic systems, biological systems. The goal of a descriptive model is to understand the behavior of the real system. In many cases it is also used as a basis for predicting future behavior. Because a model is an abstraction of a real system, data can be collected from the existing system and used as input for the model.

Prescriptive models are used to examine the behavior of man-made systems before they are built. Sketches, drawings, blueprints, formulas, and computer programs are all used for prescriptive modeling. The goal of prescriptive modeling is to examine the behavior of systems under different conditions, to understand the operational characteristics and to support the decision making process in selecting the right set of system parameters. Prescriptive modeling has to deal with two kinds of uncertainties: one is related to the question what the characteristics of the future system should be, the other uncertainty has to do with the question which aspects of a future system should be included in the model. Models used to analyze the requirements for future software systems are prescriptive models.

Static or Dynamic. Models may or may not represent situations that change with time. A static model describes a relationship that does not vary with time. A dynamic model deals with time-varying interactions.

Both static and dynamic models are used for the analysis of new software systems. Information models and object models are often static models, representing the structural data aspects of the system. Data flow models, functional models, and state-transition models are dynamic models, representing the temporal and behavioral aspects of the system.

Operational or Inoperational. Models may be divided in operational and inoperational models.

Operational models are dynamic models which can be put into effect. Operational physical models are usually working small-scale versions of objects, such as trains, automobiles, aircraft. Operational abstract models are describing time-varying phenomena. They contain descriptions how to generate the actions that are taken progressively through time. To be useful, the model must be executed by a mechanical or electronic device. An important class of executable, abstract models are simulation models which are used to simulate the current or expected behavior of a system. They are frequently used to study complex, history-dependent state-transitions, which are difficult to predict. Those models are also used to study the effects of different alternative solutions as a basis for experimental investigations.

Inoperational models are models which cannot be executed. Many models, used for the analysis of software systems are inoperational models.

 

1.2 Domain Models

Domain models are abstract, prescriptive, dynamic, and operational models of concepts in a problem area. They are used to study the structure and the behavior of a future software system under varying conditions and the implications of different concepts in the problem space.

Domain modeling may be used in addition to existing system analysis methodologies. In that case it may augment and improve the results of the system analysis process.

Domain modeling may also be used as a single and independent tool for system analysis.

Why do we need domain modeling? There are a number of important reasons to build domain models:

Increasing Complexities. The systems we are planning nowadays are increasing in complexity. The continuing growth of hardware capabilities, the introduction of new technological possibilities, and the everlasting demands of user communities are creating continuous pressures for more advanced applications. Current methods of system developments are not adequate for these new, more complex generations of applications. Domain models can help to reduce complexities.

Missing Requirements. In an ideal situation, systems analysis starts with as input a complete, formal, and unambiguous system requirements specification. In practice, the initial system requirements are often informal, ambiguous, and incomplete. The main cause is that it is difficult to foresee all the implications and interactions in the system to build. Domain modeling may help to discover missing requirements early in the development process. Model building as a means of discovering missing requirements is frequently used in other disciplines.

Global requirements are determining the structure of a system. The detailed requirements should fit within that structure. The structure determines if a new requirement can be fulfilled and the structure also 'invites' for detailed requirements to complete the structure. That means that once a structure has been defined it will act as a coherent and stable framework which separates the consistent requirements from the ones that are inconsistent with the structure.

A domain model may act as such a framework which invites for more detailed requirements from the users and which may help to discover missing requirements early in the development process. It can also be used to detect requirements which are not consistent with the implied structure, leaving the analyst with three options: either change the structure of the domain model, or discuss with the users the implications of the requirements, or do both.

Dynamic Behavior. As we saw, before a house is built a number of modeling steps are taken to ensure that the house is constructed according to the wishes of the user. The same applies to building software systems. However, there are even stronger reasons to make models before building software systems, because there are two characteristics of software systems which are not present in our building example.

A primary distinction is that while in the building industry the products are real, physical constructions, in information processing systems the software products are abstract entities. And we all know that people have more trouble to comprehend abstract concepts then concrete things.

Another difference is that in the building industry the static behavior of its products is dominant, while in computer-based systems the dynamic behavior of the systems is most important. That means that static models are not sufficient to describe a system because we know that it is often very difficult to derive from a static description the dynamic behavior and to foresee all the implications and interactions between the different parts of a running system. The essence of software, however, is its dynamic behavior! Designing complex systems using only static means is like designing an aircraft without using a wind tunnel.

In particular the combination of both characteristics makes the construction of reliable and maintainable software an inherent difficult job. The systems we want to create are both dynamic and abstract in nature. To make those systems more 'visible', we need executable domain models as simplified representations of the systems we want to build. These models should reflect the dynamic behavior of a system and may be used for experiments and study. They can also be used for interrogation to answer questions about system behavior in particular cases.

Incompatible and Partial Models. The analysis of user requirements and the translation of these requirements into proper system specifications are often determining factors for developing usable systems. As a result, many methods, techniques and tools have been developed to support the analysis activities. Many methods are based on graphical representations to specify the activities and the data of the intended system. All kinds of diagrams are used to describe certain aspects of the system, sometimes in great detail. There are many types of diagrams for data modeling, for data flow, for several kinds of activities, and so on.

However, there are a number of problems associated with these kinds of graphical representations. First of all, to support the analysis activities, more than one model is required. Models for data, supplemented by separate models for activities are often needed to model several views of a system. For example, structural, functional, and control views can be modeled. However, each model represents a partial view of the system. The total behavior of a system can only be derived by consulting a number of different models using separate notations. The translation from one model to another is often cumbersome and sometimes impossible because of lack of information. Because of these problems, the gaps in representation and meaning between different partial models are major sources of misunderstandings and errors. And we all know that errors made in the early phases of development are very costly to repair.

Domain modeling helps to solve these kinds of problems because in a domain model the static and dynamic aspects of a system are integrated into one model. Domain modeling also helps to derive from real-world concepts the corresponding information concepts.

 

1.3 Steps in Domain Modeling

In domain modeling the following steps are recognized:

* Step 1: Identify Key Concepts

* Step 2: Specify Domain Definitions

* Step 3: Specify Domain Operations

* Step 4: Implement Domain Specifications

* Step 5: System Modeling

These steps have the following meaning:

Step 1: Identify Key Concepts

  • The first step of the domain modeling process is to identify the key concepts of the problem domain. How that should be done is described in Chapter 2, "Concepts".

Step 2: Specify Domain Definitions

  • The second step is to specify domain definitions of the concepts identified in step 1. A domain is the representation of a concept in a domain model. Concepts in the problem domain are represented by corresponding domain definitions. Domain definitions are defining the relationships between different domains. How domains are defined is described in Chapter 3, "Domain Definitions".

Step 3: Specify Domain Operations

  • The third step is to specify domain operations for the domains defined in step 2. How domains operations are specified is described in Chapter 4, "Domain Operations".

Step 4: Implement Domain Specifications

  • The fourth step is to implement the domain specifications. Domain specifications consists of domain definitions, identified in step 2, and domain operations, specified in step 3. How domains are implemented is described in Chapter 5, "Implementation of Domain Specifications".

Step 5: System Modeling

  • The final step is to model the system based on implemented domains of step 4 and external events as specified for the system. How that is done is described in Chapter 6, "Systems".

The domain modeling process is in essence an iterative process. It may start with often very vague notions of the system, but after successive iterations the ultimate structure of the system should emerge. And although we have presented the modeling process as a sequence of steps, you should never forget its iterative nature.

 

1.4 Results of Domain Modeling

There are two main reasons for domain modeling. The first one is to get a better understanding of the problem domain in order to complete the system requirements. The second reason is to lay the foundation for the design of the system.

Domain modeling is used during the system analysis activities as a tool to support the analysis process of a system. It is particularly suited to study the dynamic behavior of the system and to discover unknown user requirements. As an operational model it can be subject to experiments to discover the optimal structure and behavior. Because the domain model deals with concepts of the problem space it should help to answer the question what the system should do.

Domain modeling can start as soon as the global requirements of the system are known. The global requirements are used to determine the structure of the model. All the detailed requirements should fit within that structure. The structure determines if a new requirement can be fulfilled and the structure also 'invites' for detailed requirements to complete the structure. That means that once a structure has been defined it will act as a coherent and stable framework which separates the consistent requirements from the ones that are inconsistent.

The domain model is an executable model which can be used by users to get a much better understanding of what the ultimate system will look like. Based on that model the users may agree to build that system as represented by the model. The model is also important for the developers because it gives them more insight in the kind of system they are suppose to build.

Based on the results obtained via the domain model, the system requirements may be completed. In addition, the development plan and all its documentation can make use of the results of the analysis activities.

 

1.5 Moving to Systems Design

Moving from systems analysis to systems design is a progressive expansion of the model. The domain model already defines the problem-space concepts and the associated actions. The design will use the same concepts but will transform the problem-space concepts into corresponding domain-oriented solutions.

The domain model will be expanded into an design model: it should reflect the design of the system taking into consideration the implementation aspects, such as the possible hardware and software configurations, the database management system it will use, etc. The design model deals with the solution space and it should give an answer to the question how the system should work.

In addition, the design model also used as a basis for implementation.

 

1.6 Summary

  • A model is an abstracted representation of a system. Models can be a basis for investigations at much lower cost and in less time than building the system.
  • Domain models are abstract, prescriptive, dynamic, and executable models of concepts in a problem domain.
  • The reasons to build domain models are:

* Increasing complexities of future systems

* Detection of missing requirements

* Investigations of dynamic system behavior

* One unified model for a system

  • There are 5 steps involved in the domain modeling process.
  • Domain modeling may result in a better understanding of the problem space and may be used as the foundation for the design of the system.
  • Moving from systems analysis to systems design and from systems design to implementation are progressive expansions of the model.

 

Top of Page   Part 4: Domain Modeling   Chapter 1: Introduction

 
            
Introduction

Home | Highlights of Elisa | Integrating Different Paradigms | Getting Started with Elisa | Demo's  | What is Domain Orientation | Bibliography | Copyright | News | Contact | Contents

Language Description:

Lexical Elements | Basic Data Types and Expressions | Definitions | Streams | Backtracking | Statements and Special Expressions | Arrays | Lists | Descriptors | Components | Collections | Generic Components | Terms | Categories | Types | Built-in Definitions | Higher-order Definitions | External Interfaces | Index 

Data Structures: Sequences | Examples involving Lists | Trees | Graphs | Searching State Spaces | Language Processing | Knowledge Representations
Domain Modeling:

Domain Modeling | Concepts | Domain Definitions | Domain Operations | Domain Implementations | Systems | Case study: an Order processing system | Case study: an Airport Support system | Domain Orientation versus Object Orientation

Design Patterns:

Introduction | Abstract Factory | Builder | Factory Method | Prototype | Singleton | Adapter | Bridge | Composite | Decorator | Facade | Flyweight | Proxy | Chain of Responsibility | Command | Interpreter | Iterator | Mediator | Memento | Observer | State | Strategy | Template Method | Visitor 

 

click tracking

This page was last modified on 13-05-2015 19:45:42   

free hit counter