Overview
Before 1995, a software developer had to choose between building software that was object oriented and software that had the reliability of Ada 83. By translating C++ into Ada 95, we can now achieve more reliable object-oriented software. This article describes a case study in which such a translation was performed manually. The various difficulties that were encountered are described, together with the solutions that were adopted. This article concludes with a justification for an automatic translator from C++ to Ada 95.
Introduction
One of the strengths of Ada 95 is that, unlike Ada 83, it is object oriented <1>. Before 1995, if a software developer was given the choice of implementing a software product either in C++ or in Ada 83, a trade-off had to be made. Using C++ meant that the object-oriented paradigm could be employed with all its many advantages, including maintainability and reusability of components [1]. On the other hand, Ada 83 was designed for reliable software <2>. Thus, software engineers had to decide which of the two languages was more appropriate for a given project.
Today, there is no need to choose between reliability and object orientation because Ada 95 provides both qualities. This means that the reliability of existing C++ software can be increased by translating it into Ada 95, then using the Ada 95 compiler and linker to highlight potential problems that were present in the C++ version. However, this leads to the question, "How hard is it to translate from C++ to Ada 95?" If it is as time-consuming to convert an existing software product from C++ to Ada 95 as it was to implement the original C++ version, most clients will be extremely reluctant to have their C++ software converted. On the other hand, the availability of an automatic translation tool could lead to widespread conversion of existing C++ products to Ada 95.
There is a further complication. Suppose that the translation process is so straightforward that it can be automated. If the resulting translation is hard to understand, the Ada 95 code will essentially be unmaintainable and unreusable. In theory, it is possible to translate from any one programming language into any other programming language. For example, it is certainly possible to translate from machine code into Ada. However, machine code has no variable names or procedure names, so the resulting Ada code will be incomprehensible and hence, unmaintainable and unreusable.
Thus, if translating C++ code into Ada 95 is to be a worthwhile endeavor, two criteria have to be satisfied. First, it has to be possible to automate the process (or almost all of the process). Second, the resulting code has to be readable.
This article describes a first step toward an automated C++ to Ada 95 translator. We have taken a C++ product and manually translated it into Ada 95, noting the difficulties we encountered and how we resolved them. We concluded that it is indeed possible to build an automatic tool to translate existing C++ code to Ada 95 to increase its reliability.
Terminology
C++ and Ada 95 use different object-oriented terminologies. For example, a C++ "class" contains "data members" and "member functions," whereas an Ada "tagged type" contains "components" and "primitive operations." To reduce confusion in what follows, we will use generic object-oriented terminology; that is, a class contains attributes (data) and methods (actions). A member is either an attribute or a method. With regard to C++ functions or Ada subprograms that are defined external to the classes, we will refer to them as procedures.
The Case Study
Ada 95 has improved on Ada 83 in three broad areas; namely, real-time and parallel programming, programming in the large, and object-oriented programming [2]. In this case study [3] we decided to concentrate on the last of these; that is, the object-oriented programming features of Ada 95. Accordingly, we started with a C++ data processing program that is heavily object oriented and translated it into Ada 95.
In most cases, it was possible to translate directly. For example, a while loop in C++ became a while loop in Ada 95. The C++ output statement cout was replaced by the Ada 95 command Put. Even when it came to the object-oriented parts of the program, there were only a few difficulties. Figure 1 shows selected metrics for the original C++ product and its Ada 95 translation.
| Metric | C++ | Ada 95 | Lines of code | 2,381 | 2,883 |
|---|---|---|
| Number of classes | 7 | 7 |
| Number of methods | 60 | 60 |
| Number of procedures | 15 | 15 |
| Figure 1: Metrics for C++ Product and its Ada 95 Translation. | ||
Figure 1 reflects a key result; namely, that it was possible to do a direct translation of C++ classes into Ada 95 tagged types. However, a number of problems arose both within the context of the objects and in the software in general.
Problems with Object-Oriented Constructs
The first difficulty we encountered is that an additional variable name has to be provided when translating a C++ class into Ada 95. For example, Figure 2 shows class officer_class as defined in C++ and its translation in Ada 95 as a tagged type. This shows the need for an additional name, that of the tagged type. When doing a manual conversion, it is easy to check that the name of the new type, officer in this example, is unique. However, if the translation is automatically performed, the software must assign a new name. There are two ways to do this, neither of them totally satisfactory. One is for the translation program to be interactive rather than totally automatic and to ask the user to supply a name for each tagged type. The other is for the program to supply a unique name. To ensure uniqueness, such a name may be something like officer_class_&&&_234. Though unique, this sort of name sharply reduces the readability of the resulting Ada 95 code.
| C++ Code |
|---|
| class officer_class { ... } |
| Ada 95 Translation |
| package officer_class is type officer is tagged private; ... end package officer_class; |
| Figure 2: C++ Implementation of officer_class and its Ada 95 Translation. |
A second problem arose from visibility considerations. C++ supports three levels of visibility of the members of a class, namely private, protected, and public. If specified as private, a member is visible only within the class. A protected member is visible within the class and also within any of its descendants in the inheritance tree. Finally, a public member is visible everywhere that the class is visible. Ada 95, however, supports only the concepts of private and public visibility.
The C++ keyword protected can occur in a second context; namely, that of an access specifier for inherited members (attributes and methods). Each derived class in C++ is either a private, protected, or public descendant of its base class. The access specifier can modify the visibility of the members within the derived class. For example, if the access specifier is protected, the visibility of members declared to be public within the base class becomes protected within the derived class.
Thus, when translating from C++ to Ada 95, what is needed is not only a mechanism to implement the C++ concept of protected visibility in the Ada 95 translation, but also a mechanism to change visibility within an Ada 95-derived class. We adopted the solution described in [4]. This approach is complex and requires detailed knowledge of the intricacies of the Ada 95 visibility rules; accordingly, the interested reader should consult [4] for details. The key issue is that, notwithstanding its difficulties and subtleties, this solution can be directly implemented using an automatic translation tool.
Other Problems
In C++, global types, subtypes, and functions are declared in an unnamed global block that is external to any object. This concept does not exist in Ada 95. Accordingly, in our case study we had to set up a separate specification package that contained these declarations. A with clause could then be used to make this global package visible when needed in an Ada 95 package. If an automatic translation tool is used, it would have to include this global package in every Ada 95 program unit, whether needed or not. The presence of unnecessary and irrelevant statements in the code will reduce readability and hence, maintainability. Reusability will also be compromised.
Another problem arose from file input and output within the C++ product. After the command is given to open file my_file, the C++ product tests whether the file exists. Specifically, the command if (my_file) checks the effect of the open command. This is to ensure that if for some reason the file does not exist, the product will not terminate in failure. There is no corresponding Ada 95 command, because Ada is a real-time language. Thus, if there were a File_Exists function, it would be guaranteed correct only at the instant that the function is executed. In a multiuser system, the file may have come and gone by the time control is returned from the File_Exists function [5].
Because our case study is a single-user, non-real-time system, the solution we adopted was to check manually before running the program that the necessary files exist and, if not, to create them. This is entirely unsatisfactory, but it worked because the tests for the existence of the files were simply error checks; the logic of the product did not depend on them. In the case of an Ada real-time product, the solution is to use exception handlers. It is not clear that this can be adequately done by a fully automatic tool; an interactive translator may be required.
Finally, the strong typing of Ada 95 caused some problems with input and output in general. In C++ (as in most languages), an input or output statement can take several arguments of different types. For example, consider the C++ statement shown at the top of Figure 3. The stream output command cout has three arguments, namely, a literal string "SELLING PRICE: ", a floating point variable sell_price and the newline instruction endl ("end of line").
In Ada 95, an input or output command can indeed take multiple arguments, but all of them must be of the identical type; namely, the type that is specific to that input or output command. This is reflected in the translation into Ada 95 of the C++ statement as shown at the bottom of Figure 3. Three separate Ada instructions are needed to output the text, the floating-point number, and the newline instruction.
| C++ Code |
|---|
| cout << "SELLING PRICE: " << sell_price << endl; |
| Ada 95 Translation |
| Text_IO.Put ("SELLING PRICE: "); Flt_IO.Put (sell_price); Text_IO.New_Line; |
| Figure 3: C++ Output Statement and its Ada 95 Translation. |
Results and Conclusions
With the exception of the problem of testing for the existence of a file, we were able to translate the entire C++ product into Ada 95. Furthermore, most of the translation was direct; that is, each C++ statement could be translated into an equivalent Ada 95 statement. The hardest part of the task was to determine how to handle the C++ protected visibility level. Other than that, the translation process proved to be relatively straightforward.
As shown in Figure 1, the major difference between the two versions is that the Ada 95 translation is 21 percent longer than the C++ original. There are three reasons for this. First, each Ada package consists of two parts: the package specification that declares the various members of the package (data types and subprograms) and the package body where the functionality of the package is implemented. The seven-package specifications added considerably to the overall number of lines of code. Second, as explained at the end of the previous section, each C++ input and output statement with arguments of different types had to be replaced by multiple Ada 95 input and output statements. Third, C++ supports inline code in a class declaration to implement so-called member access functions in an efficient manner. In Ada 95, this inline code has to be implemented as primitive operations in the package body. In the case study, each of the 27 inline access functions required three or four lines of Ada code.
The key aspect of this work is that, based on our case study, we believe we can construct an automatic tool that can translate a C++ software product into Ada 95 with minimal human intervention. Furthermore, the resulting Ada 95 product will be readable and hence maintainable and reusable.
In the world of object-oriented software, Ada 95 is currently a relatively small player. Both C++ and Smalltalk have years of head start on Ada 95. Furthermore, Ada has been viewed from the beginning as a real-time military language, rather than as an all-purpose language that can be used for real- time embedded software in the military domain, among many other application areas. Use of such a proposed C++ to Ada 95 translator would therefore have two immediate positive effects.
First, it would increase the reliability of production-mode software currently implemented in C++. The Ada 95 compiler and linker would highlight potential problems in the translated code. Unlike a tool such as Lint, which detects potential problems essentially at the statement level in C++, this mechanism would operate at three levels; namely, the statement level, the subprogram level, and the program level. This would result in considerably more reliable code.
Second, the proposed C++ to Ada 95 translator would greatly increase the quantity of production-mode Ada 95 software, thereby giving Ada 95 a more visible role in the object-oriented world. Ada 95 would no longer be a bit player on the object-oriented stage but would be able to play a leading role in modern software technology.
Dr. Stephen R. Schach
Computer Science Department
Vanderbilt University
Box 1679, Station B
Nashville, TN 37235
Voice: 615-322-2924
Fax: 615-343-5459
Internet:srs@vuse.vanderbilt.edu
About the Authors
Ensign Kimberly K. Uhde recently earned a master's degree in computer science from Vanderbilt University and is a graduate of the U.S. Naval Academy. Uhde is receiving further training at the Navy's Surface Warfare Officer School in Newport, R.I. before she reports to the destroyer, USS David R. Ray, which is homeported in Everett, Wash.
Dr. Stephen R. Schach is an associate professor of computer science at Vanderbilt University. He is also a software engineering consultant with over 25 years of computer experience. He consults for industry and gives seminars worldwide on the object-oriented paradigm, CASE, software reuse, and software reengineering. Schach has published over 80 refereed technical papers. The third edition of his book Classical and Object-Oriented Software Engineering was published by Richard D. Irwin in August 1995.
References
Notes