Mapping UML to Ada-an insight into a tricky issue. (Software Intelligence).
The UML has become the industry standard language for constructing models in a software intensive system. Today, many UML tool sets support Code Generation from a model to the appropriate programming language (Forward Engineering). The toolsets on the market today offer a number of different approaches, but it is important to understand the principles involved. In an ideal world, the UML modeller should not be concerned with the implementation language, so it is important to understand that the UML defines the logical structure of the software, and not an exact implementation. Some relationships in UML (Inheritance for example) do not have direct support by some programming languages (C, Ada83) but can still be implemented by carefully considering the mapping rules.
When generating code, normally the Class Diagrams are used to extract the implementation details. When I teach this subject I talk about how to map a class (along with its attributes, operations and associations) to the relevant Ada language components and functions. I teach the importance of avoiding overcomplicating the model with Ada specific references - mapping rules should be established and applied to "pure UML".
It is without doubt that mapping to languages such as C++ and Java is a far more routine task. However, as a strong advocator of Ada as a rich and reliable programming language I believe that the napping from UML is a challenge worth embracing. Below I have provided a detailed technical insight into the mapping of Ada to UML
The simplest form of a class is a simple discrete type, e.g. "range 0....3" which would be be represented as an ordinal type, such as type Object is range 0.3
Generally, classes are transformed into types declared in library packages, utilities are transformed into library packages, attributes and relationships are transformed into record components and the methods are implemented as functions or procedures. The main source of information for the implementation is the class diagram. Classes are transformed into record types declared in library packages. The library package name is derived from the name of the class (the package where the type and operations associated with the class are declared) and the name of a type (the type associated with the class) typically is called "Object".
Attributes are transformed into record components and methods are transformed into operations taking the class type as a parameter (plus any additional parameters defined by the operation signature). If the subprogram updates the object; i.e. changes any of its attributes, then the parameter mode must be specified as either 'in out' or 'access'. Access parameters are an efficient method of designating the instance on which the operation is being performed. To support best practices of software engineering, namely data hiding and encapsulation, the record type is named in the public part of the package specification and the full type is declared in the private part. For private attributes, the only method by which the attribute can be written to or read is through an accessor operation.
States that any object can access the attribute or operation. Public visibility is specified in the UML with the '+' symbol. If the attribute or operation has no symbols associated with it; you can usually assume it is public. Public attributes are implemented by accessor operations declared in the visible part of the specification. Public operations are declared directly in the visible part of the package specification.
States that only the object itself can access the attribute or operation. Private visibility is specified in the UML with the '-' symbol. It should be a design aim to ensure that only those attributes and operations that are needed by other classes are visible. The aim should be to use the most restrictive visibility possible. Private entities are always declared in the private part of the specification.
States that only descendants of the class can access the attribute or operation. Protected visibility is specified in the UML with the '#' symbol. A descendant (or subclass) is one with an inheritance relationship to the class for which the visibility is being specified. Protected entities are declared in the private part of the package specification and subclasses implemented as child packages to gain visibility of the parent.
Another important detail that can be specified for a class's attributes and operations is its owner scope. The owner scope specifies whether the feature appears in each instance of the class or whether there is just a single instance of the feature for all instances.
In the UML, you can specify two kinds of scope: Instance--Each instance holds its own instance of the feature Classifier--There is just 1 instance of the feature
The UML notation for classifier scope is to underline the attribute or operation; no underline means the feature has instance scope. In general, most attributes and operations have instance scope. The most common use of classifier scope is for private attributes that must be shared amongst a set of instances, for example a constant value of an attribute that all classes use to ensure all classes use the same value.
Class scope attributes are implemented as global variables in the package that declares the type which represent the class. An attribute is included in the type, which is normally an access type that designates the class scoped attribute.
Objects are simply instances of classes and are therefore variables declared in the program. When calling methods on an object, the object is passed as a parameter to the corresponding subprogram.
If access parameters are used, then the objects must be marked as aliased
Inheritance is probably the single biggest difference between functional/procedural languages and Object-Oriented (00) languages. Inheritance allows a new class to be created or derived from a previously-defined base class.
Derived classes may (and typically do) extend their base class implementation, i.e. additional attributes and behaviour ran be added to a derived class. A derived class may also be derived from itself. This structure of derived classes is called an inheritance hierarchy; the further down the hierarchy, the more the specialised the classes become; the higher up the hierarchy, the more general the classes become.
A variant record can be used to implement the generalisation hierarchy.
Ada provides numerous language features to support inheritance. One method (which can be used with Ada83) is using variant record, in which an enumeration type is declared that lists all the classes in the relationship and the variant record structure reflects the generalisation tree.
Ada95 provides direct support for inheritance through the use of tagged types when using tagged implementation, each class corresponds to a tagged type. If the class is the base class, i.e. the root of the inheritance hierarchy, the type includes the keyword tagged. The class is tagged, which means it can be derived from and extended. The word tag is derived from Pascal, where it is used to denote a component of a record distinguishing different variants of the type, in fact the tag is a hidden discriminant. Using tagged types provides a more flexible form of derivation where it is possible to add additional attributes as well as operations. In essence, a tree of types can be created, where each type contains all the components of the parent plus additional ones. Certain operations on a type are known as primitive operations of that type, they are operations declared in the same region as the type, and which have parameters or a result of the type. On derivation these primitive operations are inherited by the new type. Sometimes we want to replace the inherited behaviour, in Ada terms, this is known as overriding. This new version becomes a primitive operation of the new type and are themselves inherited by any further derived type.
The word polymorphism comes from the Greek for "many forms." Most associate the term with an object's ability to magically execute the correct method at run time. At run time, the program determines which actual implementation to execute, based on the type of object manipulated. Late Binding or Dispatching. Polymorphism is also known as Dynamic Binding.
Each Tagged type has an associated type denoted by T'Class which comprises the union of all the types in the tree of derived types rooted at T. The value of T'Class are the values of T and all its derived types the type T is known as the root type of the class. It is fundamental in class wide programming to manipulate objects via access types (references), this is largely because objects will typically be different sizes. When the access type is dereferenced, the tag is used to determine the type of object being designated. Calling a primitive operation on the base class when dereferencing the access type will cause the appropriate operation to be called. This run time choice of procedure call is called dispatching and is the key to the flexibility of class wide programming.
An abstract class is one that exists for other classes to inherit from. You cannot create instances (objects) of abstract classes but can derive (inherit) from them. Classes that are derived from abstract classes from which objects can be created are known as concrete classes. Ada95 provides direct support for Abstract classes and operations through the use of the keyword Abstract.
Associations are structural relationships among instances of a class. Given an association connecting two classes, you can navigate from an object of one class to an object of another class. Graphically (in UML) an association is rendered as a solid line connecting the same or different classes.
In Ada, associations are typically implemented as record components. The actual implementation of an association depends on whether the association is specified as composition or aggregation and how the association has been named.
Composition is implemented using the type associated with the class that is the 'part'. Depending on the multiplicity, the relationship will be implemented either directly or through a container.
Aggregation is implemented through Ada95 access types that designate the class which is the 'part'. Again, the actual implementation will depend on the multiplicity specified for the association. Normally, access types are declared in the same library unit that defines the type for the class, this ensures that one access type is declared, even if the 'part' class participates in many different associations.
An alternative method of implementing a multiplicity of greater than one is through the use of a discriminated record, where the discriminant represents the number of instances currently associated. If the multiplicity was exact, thc array bounds would be static and therefore an access type would not be required.
A template class is the description of a set of classes and can have one or more formal parameters, shown in the dashed box in the top right hand corner. A class can instantiate a template class by binding to the formal parameters, the parameters passed are known as the actual values. Objects cannot be created from template classes, i.e. a template class is not a directly-usable class, it is a class from which other classes are created.
Template classes are graphically represented as a normal class with a small dashed rectangle on the upper right-hand corner of the rectangle for the class, The dashed rectangle contains a parameter list of formal parameters for the class.
The template class is implemented as a type declared in a generic library package. The formal parameters of the class specify the generic formal parameters. The class attributes define the record components in the tagged typo (if tagged implementation is being adopted) and the operations are implemented as primitive operations on the tagged type declared in the generic package specification.
Using generics, the binding class is a library level generic instantiation. The actual parameters are taken from the binding class specification. Bound classes are fully specified by the template to which they are binding, therefore the instance of the binding class provides all the types and operations specified by the template class.
The Subclasses am also implemented as tagged types declared in a generic library package. However, there are two possibilities to consider:
1 The subclass is not implemented as a child package of the base class. The subclass must import the base class package as a generic formal parameter.
2 The subclass is implemented as a child package of the base class. The formal parameters only include the new parameters specified by the subclass. The subclass has direct visibility into the base class and can therefore see the types declared in its specification and therefore does not need it passed as a formal parameter.
Concurrency refers to speeding up the execution of a program by dividing the program in multiple fragments (tasks) that can execute simultaneously. These tasks can execute on a single processor or across multiple processors. A program that is executed across multiple processors should execute faster than it would using a single processor. Concurrency specifies multiple threads of control executing simultaneously and independently. However, Co-ordination is required when concurrent activities converge or interact.
In the UML, you model each independent flow of control as an active class (object) that represents a thread or process that can initiate control activity.
Active classes are implemented using Ada95 task types, with the following rules-.
* The type that represents the class contains the class attributes and a task that represents the active element
* The guarded operations are transformed into entries on the task type
* For each visible guarded entry, a procedure is declared in the visible part of the package that declares the task type and an entry is declared in the task type. The procedure has the same signature as the entry, except the procedure has an additional parameter that designates the object being operated on. The body simply calls the corresponding entry.
Guarded operations are implemented as the entry points on the task. Each operation is treated by the object (that participates in multiple threads) as a critical region. A critical region is a section of code in a program that must be executed while no other piece of code is running. Often while the program is executing in a critical region all interrupts are disabled. For real time systems, it is important that the length of time the flow of control is in a critical region should be kept as short as possible. To implement concurrent operations using Ada95, protected types with the following rules:
Ada provides a means to communicate with the outside world, i.e. interface to other programming languages such as assembler, C or Fortran. For this type of communication to occur, it must be possible to define the convention used to represent the data and an interface between the programming languages.
The pragma Import indicates that there is an external operation to the Ada program and specifies the language in which it is written. There is a corresponding Export, which makes Ada subprograms externally visible. Pragma Import and Export have additional parameters, for passing the name of a foreign language subprogram and the link name if they differ from the Ada name. Pragma convention specifies the convention that should be used to represent data structures to ensure compatibility between interfaces.
Derek Russell began delivering consulting and mentoring services at BAE Systems, where he worked closely with Eurofighter project teams across Europe. He has a wealth of experience leading major technology based defence projects, such as Eurofighter, Harrier and various Command & Control systems. He was responsible for the original IPU architectural and Detailed Design and wrote a significant part of the software as well as guiding others. He has an in-depth understanding of Eurofighter standards and procedures and in many of the subsystems, especially the IMRS and CSMU, he was instrumental in helping the first development aircraft (DAO2) achieve first flight. In 1999 he co-founded Objektum with Andy Bissell
|Printer friendly Cite/link Email Feedback|
|Date:||May 1, 2003|
|Previous Article:||Print Watch 2.36. (Software Intelligence).|
|Next Article:||Securing electronic messaging. (Software Intelligence).|