At the beginning of the project, a careful consideration was made as to the choice of programming languages, techniques and platforms.
The specifics of our market is that the potential customers have good financial resources and can afford significant investments into computer hardware. Also, the cost of software for them would exceed the cost of hardware on which this software will be run.
The estimate about the staff needed to implement the project was about 10-20 developers.
It was expected that the software would extensively use client-server architecture and relational databases. An additional complication was that the potential cutomers were using different relational databases, such as Oracle, Sybase or Informix. It was unfeasible to require them to buy a specific database server to be able to use our applications.
A strategic decision was made to use object-oriented technology for software development.
Two programming languages were considered - C++ and Eiffel. The evaluation criteria consisted of the following parts:
The portability issue has two parts. One is the ability of programs to interact with parts of different platforms, for example with filesystems and window systems, and services, such as different DBMS's. All systems offer their "native" programmer's interface in the form of C libraries and include files. This seemingly gives an advantage to C++. However, interfaces for different platforms are largely incompatible and require an additional layer of code hiding this incompatibility.
The implementation of such a layer would have the same cost in both C++ and Eiffel. However, since the functionality of this layer is used everywhere in the software system, the cost of its use in development and its simplicity are the prime concern. It was reasonable to expect that an Eiffel class library would be easier to use than a C++ library, and thus to have less cost of use. As well, since it was anticipated that this layer will evolve in parallel with the main part of the system, problems of dependencies were also considered.
As an example, it is much easier to redefine the interface of child and parent classes in Eiffel than in C++ if the development of such classes is done by different people. In C++, to redefine an inherited function correctly, it must be explicitly declared virtual in a parent class. In Eiffel, no change in the parent class is required. When we consider organizational overheads of such change, we clearly see the advantage Eiffel offers us.
The easiest part of compatibility is hardware compatibility. Both languages offer good solutions for these problems, and we know many programs that work across an immense number of platforms. No language has a clear advantage in this respect, although C++ offers better flexibility with its basic types.
In general, Eiffel is clearly superior to C++ for solving compatibility problems and isolating the compatibility issues.
Efficiency in use of CPU time and memory was also given highest priority. It was anticipated that the computations would be a big obstacle for interactive users.
Considering the use of C/C++ vs. Eiffel it was concluded that it was inappropriate to use Eiffel as the language for computations. It was necessary to keep large amounts of objects needed for computations but invisible to the end users. The garbage collection overhead, comprized of time to traverse all these objects and memory use for object headers and descriptors in garbage collector tables made it impossible to use Eiffel for implementation of such objects. Also, the measurements made to compare the time of array access had clearly shown the advantage C/C++ had over Eiffel.
A decision was made to isolate the numeric part of the application from the interactive part. The objects and algorithms of the numeric part had been clearly defined and implemented in C (not C++). The interface between numerical library and Eiffel libraries had been defined and implemented.
Therefore, even though C was used as the main language for the numerical part, it was not an obstacle to the development of the rest of the system in Eiffel.
The real-world issues of learning curve and organization of development were also a strong push for Eiffel. Although there were a number of candidates already proficient in C++, actual staffing of positions with C++ people was not easy. A training in OOP/OOD and a particular language was a necessity no matter what language would be used in the project. It was clear that the expense to teach staff members the principles of OOD and syntax of programming language is much lower with Eiffel than with C++.
This article is not the appropriate place for advocacy of Eiffel vs. C++ in terms of reusability, interoperability, and maintainability, but both the author's experience and general opinion favors Eiffel over C++.
The cost of development and maintenance was obviously one of the most important aspects of the language decision. Eiffel offers a much simpler syntax. It also forces a programmer to use object-oriented design. From our experience, it is easier to formulate and implement classes in Eiffel. As well, Eiffel greatly simplifies the use of computer resources. The garbage collector takes care of freeing memory.
Memory management in C++ usually leads to one of two extremes: either to the need for all modules to know the internal information about who and when needs what objects, or to active copying of objects between modules to avoid this problem. The garbage collection in Eiffel elegantly solves this problem. Besides apparent technical advantages, it greatly reduces development and maintenance costs and the number of potential memory use problems.
The mechanism of assertions also has a great impact on the cost of software development, helping to catch at least 70-80% of potential bugs in the early stages of development. It also dramatically improves software quality.
The natural way of development of such a project would be development of several libraries. The simplest examples of such libraries are dabatase connectivity and a windowing library, belonging to the compatibility layer. Note that the windowing library also includes the part responsible for representation of complicated objects such as tables (spreadsheets) and graphs, and this part does not belong to the compatibility layer.
As a side note, the windowing library developed at ULTER Systems is called EPWL (Eiffel Portable Windows Library) and is now available as a separate product. It has been extensively tested and modified to adopt necessary changes and now is a robust tool for any Eiffel developer who needs to create portable and GUI-rich applications.
The disadvantage of Eiffel (or, to be more exact, of the Eiffel implementation that we used) was that it is impossible to create precompiled libraries in the way that developers use in C++.
However, the general conclusion from the cost analysis again leads us towards the choice of Eiffel.
After considering all of these factors Eiffel was the natural choice for the project.
The Eiffel system being distributed includes only a compiler, and it does not include such amenities as an interactive debugger, an integrated development environment or CASE-like tools.
Its runtime system consists of two layers. The first gives an interface to the produced C code, and the second gives an interface to operating system services, such as file i/o operations and memory management. It makes the Eiffel runtime system extremely portable and does not hinder the performance.
Currently, the following platforms are supported:
The compiler utilizes mark-and-sweep garbage collection strategy.
It brings an overhead of adding and removing objects described in the 'local' sections of features. Objects are added and removed to and from a so-called call chain each time a feature is called and the control is returned. This overhead is specific to the garbage collection mechanism, but not to the compiler.
However, along with some pure compiler bugs (some of them described in the 'bugs' section), there are some deviations from the Eiffel standard.
One of them is a quite innocent change in treating semicolons in Eiffel source code. While Eiffel standard is very strict about separating statements and assertions by semicolons, SiG compiler merely ignores them. Although any program conforming to Eiffel standards regarding the use of semicolons can be parsed by SiG compiler, the reverse is not true. A program that passes the syntax analysis stage of SiG compiler will not necessarily be compiled by another Eiffel compiler.
The following example can be compiled by SiG compiler:
i ; := i ; + ; 1 j ; := j - ; i;because the compiler ignores semicolons entirely in feature sections of class declarations.
A quiz: What output will this program print?
class HELLO inherit BASIC_IO end; creation run; feature run is local a : REAL; do a := + 5; put_int( a ); end; end -- classIf you used [now obsolete] version 1.2 instead of current 1.3, you would be slightly surprised by the result. It would print 0. After I checked the C code produced by the compiler, it turned out that it was calling function '+' that has never been tested because it 'seemed' obvious. This is the funniest compiler bug ever discovered by the author of this article.
There are several dozen compiler bugs that have been discovered by users. It is worth noting, hovever, that most of them are easily detectable and apply to unusual situations. Also, SiG Computer GmbH has been very responsive and has corrected most of them in subsequent releases.
Most of bugs in version 1.2.* do not exist in version 1.3.
However, it is a memory hog. On a source code including about 600 classes it achieves satisfactory performance only with approximately 32 megabytes memory. For IBM PC 486 working under Windows NT operating system, the compilation time largely depends on the amount of available memory:
Memory size Full compilation time (hrs) including C compilation 16 MB 5 hrs. 32 MB 1 hr.Usual benchmarks such as the number of lines of code (LOC) translated per second cannot be directly applied to Eiffel compilers, because unlike compilers from many other languages, Eiffel compilation supposes (but does not necessarily include) the analysis of the entire class system being compiled.
As a general note, it is entirely possible to use the Eiffel compiler version 1.3 from SiG Computer GmbH as a tool for large-scale industrial software development.
All trademarks here belong to their respective owners.
Special thanks to Mr. Klepikov ( klm@blaze.cs.jhu.edu ) for his interesting comments about SiG compiler and compilation of OO languages.