This site's content was compiled from 1993 to 2006. Beyond that, Google is your friend.
This article previously appeared in Eiffel Outlook magazine, Volume 1 Number 3, August 1991, and has been lightly edited for this presentation.
SiG Computer GmbH, Germany, started work with Eiffel in 1989. SiG decided in spring 1990 to develop an Eiffel compiler of its own. It was written in C and finished in September 1990. Since it was clear by then that the Eiffel 3.0 language definition would be released soon, we decided to write another compiler. This became the Eiffel/S compiler. It is written almost entirely in Eiffel.
This article is not a complete introduction to SiG's system. The libraries deserve a more comprehensive treatment; only some selected examples are given here to explain our views.
The compiler will be the only tool in the first release of Eiffel/S. Our long-term goal is to provide a programmer's workbench that will support fast prototyping and testing. It will be possible to ask all kinds of questions about a system, individual classes, features, etc.
Traditional browsers (graphical or not) are not sufficient when it comes to asking the more intricate questions about a system. We don't say that browsers, class abstracters and the like are not useful, but how do you get an answer to a simple question like "who uses the value of attribute A from class C"?
To this end, the current compiler puts its output (except for the C-code) into a database rather than flat files. A lot of fine grain information is produced by the compiler. Since it is already organized in a database, our future tools will allow you to explore your systems in depth.
There can be no doubt that the success or failure of any object-oriented approach to software construction in the end will depend on the quality of the supporting libraries. The authors of the Eiffel/S libraries regard the following principles as crucial and have tried to assure their realization in the Eiffel/S libraries.
The classes should be easy to use. The sheer numbers of classes to learn are often a hindrance. Large numbers of very similar classes can greatly impede a software designer's or implementor's decision making process about which class to use in a given situation. Thus, the library ideally should consist of a relatively small number of roughly orthogonal classes, each optimally suited to do its respective job.
For example, in at least 90% of all cases where one uses lists or arrays, all one really wants is a place to store an object for a while in order to access it later. That is what the ADT (abstract data type) COLLECTION offers. Ideally, there should be one class COLLECTION that does this job as efficiently as possible so that a software designer will have no qualms about using this class in 90% of the cases that arise. Of course, our library also includes ADTs like STACK, QUEUE, PR_QUEUE etc, that cover almost all of the remaining 10%.
The algorithms encapsulated in a class should be the best ones available today. Sometimes there is no best algorithm; one is better in situation A and another is better in situation B. In this case, one can justify offering two similar classes, each encapsulating one of the two good algorithms. The documentation should clearly state which class is to be chosen for which situations.
An example in the Eiffel/S libraries occurs with the pattern matchers. The Knuth-Morris-Pratt algorithm guarantees linear behaviour (linear in the length of the text to be searched) even in the worst case. On the other hand, Boyer and Moore's algorithm has a poorer worst case behaviour (O(mn), m = length of the pattern, n = length of the text), but is often faster than Knuth-Morris-Pratt in many practical applications. Thus, both algorithms are offered in appropriate classes.
The documentation should give the software designer and implementor all the information needed to decide whether to use a given class. The documentation includes a prototype of each routine with argument types, etc and the pre- and postconditions. It also includes as accurate an estimate of the complexity (space and time requirements) of the routine as one can give. It also includes a description of the algorithm used and, if possible, a literature reference where a more thorough treatment of the algorithm can be found.
It is our firm conviction that employing inheritance merely to reuse code that already exists in another class is abuse of the mechanism. This principle is likely to stir up some controversy in the Eiffel community. We strongly believe that the inheritance relationship between classes should reflext a logical structure in the software system. Consequently, we have used a client-supplier relation more often than others probably would.
The classes in the libraries must be platform-independent. Adaptations needed to deal with idiosyncracies of various platforms must be hidden beneath the surface, typically in external C routines. Graphics libraries are particularly affected by this last. A graphical library that runs only on a HP 9000, or under Sun NeWS or Microsoft Windows, has limited appeal to a developer trying to produce software for as large a market as possible.
Writing good libraries is a very demanding discipline. Writing libraries that meet the above criteria takes time - often a great deal of time. We believe that no one is served in the long run by the introduction of hastily constructed libraries that do no meet these standards. Consequently, SiG will not deliver any graphics library in the near future, but we will participate in a research project on graphical user interfaces that should result in a platform independent graphics library.
Here are some examples of clusters that will be provided with the first release of Eiffel/S.
A container class's user should not have to say in advance how big the container should be or ever have to be bothered with expanding or shrinking the container. All this should happen automatically. Why else have a language with dynamic object creation and automatic garbage collection?
The containers have three characteristics that are orthogonal to one another:
Are the elements in the container unique or can duplicates exist? The creation routine 'make' for these classes takes a BOOLEAN argument that establishes whether uniqueness is to be maintained. If this argument is true, it does not mean that it is an error to try to add an element to the container repeatedly; it simply means that the container will not react to the second and all subsequent add requests for the element.
Does one search for the element itself or does one search using a key? This property of containers is distinguished by the names COLLECTION and TABLE; in the former, the element itself is searched for and in the latter a key is used.
Are the elements in the container ordered? This can impact the performance of the add and search operations and certainly affects the semantics of the ITERATOR objects.
Classes COLLECTION, SORTED_COLLECTION, TABLE and SORTED_TABLE are intended to cover nearly all needs for containers that will normally arise. As mentioned above, other container ADTs are also provided.
These classes' actual implementations were chosen to be as efficient as possible. However, the programmer may influence which implementation will be chosen for any of these classes simply by using the mechanisms the Eiffel environment provides.
Directed and undirected graphs occur in many applications. On the other hand, efficient algorithms for solving graph-related problems are rather tricky. Thus, this is an area calling for a tested and dependable library that encapsulates the best-known algorithms for important graph-related problems.
The Eiffel/S GRAPHS cluster includes iterators for Breadth First Search and Depth First Search as well as routines for computing minimal spanning trees and shortest paths in weighted graphs. At a later time, algorithms for dealing with flow problems may be added.
This cluster encapsulates various algorithms used to search for a given substring in a string: Rabin-Karp, Knuth-Morris-Pratt, Boyer-Moore and regular expressions. We explain above our reason for providing several different implementations in this case.
In our view, a file is nothing but an array, permanently stored on some device. Thus the class FILE is generic, like class ARRAY, and offers almost the same features. Elements are stored and retrieved by an integer index. Of course, complex objects are automatically stored (recursively) with all the objects they refer to via attributes. Unlike arrays, however, objects can be put at any arbitrary positive index. There is no "resize" operation. If you put an element at index 100 and another at index 100,000, the file will not be "filled" in between. It uses only the space necessary to store two objects plus some bookkeeping information.
Files of basic type (INTEGER, etc.) are automatically treated as ordinary flat files without any additional "bureaucratic" information stored in the file.
All the information traditionally considered part of a file, like permissions, timestamps, etc., do not belong to the class FILE. This information is not an intrinsic property of a file, but rather part of the bookkeeping provided by the operating system. The class FILE_SYSTEM models these aspects of the operating system. It offers services like directory reading (resulting in a collection of strings), file renaming, and so forth.
The Eiffel/S runtime system provides an encapsulation of the operating system. The runtime system's interface is platform independent and offers the opportunity to write external C routines in a completely platform-independent way.
As a result, you can freely move both Eiffel and C code between Unix, MS-DOS, ATARI and OS/2 (provided you have the respective compilers and runtime systems). Of course, you are free to call operating system services directly, but this should almost never be necessary.
(This article is no longer available from its original source. If anyone has any objections to it being hosted here, please contact roger@eiffel.demon.co.uk)