Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
EIFFEL:
Bertrand Meyer
Routines are further divided into procedures maywithdraw (sum: INTEGER): BOOLEAN is
(actions, which do not return a value) and functions -- Is it permitted to withdraw sum
(which return a value). Here may_withdraw is a -- from the account?
function with an integer parameter, returning a do
boolean result; the other three routines invoked are Result := (balance >= minimunubalance)
procedures. end ; -- deposit
The above extract of class X does not show end -- class ACCOUNT
whether, in class ACCOUNT, balance is an attribute This class includes two clauses: feature, which
or a function without parameters. This ambiguity is describes the features of the class, and export,
intentional. A class such as X , said to be a client of which simply fists those features which are available
ACCOUNT, does not need to know how a balance is to clients of the class. Non-exported features are said
obtained: it could be stored as attribute of every to be secret. Here procedure add is secret, so that
account object, or re-computed by a function, accl.add (-3000) would have been illegal in X.
whenever requested, from other attributes such as Similarly, attribute minimumbalance is secret.
the list of previous deposits and withdrawals. (Selective export of a feature to some classes only is
Deciding on one of these implementations is the also possible.)
business of class ACCOUNT, not anybody else's. Let us examine the features in sequence.
Having shown class usage, we now present the Routines are distinguished from attributes by having
definition of the class itself, which might look like a clause of the form is...do...end. Thus balance is
the following. Following the Ada convention, fine in fact an attribute. The clause is 1000 introduces
segments beginning with -- are comments. minimumbalance as a constant attribute, which will
class ACCOUNT export not occupy any physical space in objects of the
open, deposit, may_withdraw, class. Non-constant attributes such as balance do
use space for each object of the class; they are
withdraw, balance, owner
similar to components of a record in Pascal.
feature
balance: INTEGER . Attributes balance and minimum_balance are
declared of type INTEGER. Eiffel is strongly typed:
minimum_balance: INTEGER is 1000 ;
every entity is declared of a certain type. A type is
owner: STRING ; either simple, that is to say one of INTEGER,
assign_owner (who: STRING) is REAL, CHARACTER and BOOLEAN, or a class.
-- Assign the account to owner who Arrays and strings belong to the second category;
do they are described by predefined system classes,
owner := who ARRAY and STRING, treated exactly as user-defined
end ; -- open classes with one exception: a special notation, as in
"John", is available to denote literal string constants.
add (sum: INTEGER) is
-- Add sum to the balance Automatic initialization is ensured by the
language definition, so that the initial balance of an
-- (Secret procedure)
account object will be zero after a Create. Numeric
do
attributes are initialized to zero, booleans to false,
balance := balance+sum
characters to the null character; those of class types
end ; -- deposit
are initially void.
deposit (sum: INTEGER) is
The other five features are straightforward
-- Deposit sum into the account
routines. The first four are procedures, the last one
do
(may_withdraw) a function returning a boolean
add (sum)
value; note that the special variable Result denotes
end ; -- deposit
the function result. It is initialized on function entry
withdraw (sum: INTEGER) is to the default value of the appropriate type, as
-- Withdraw sum from the account defined above.
do To properly understand the routines, it is
add (-sum) necessary to remember that in an object-oriented
end ; -- withdraw languages any operation is relative to a certain
object. In an external client invoking the operation,
this object is specified by writing the corresponding
-88-
entity on the left o f the dot, as accl in class ACCOUNT export .... (as before)
accl.open ("John"). Within the class, however, the feature
"current" object to which operations apply usually -- Attributes as before:
remains implicit, so that unqualified references, such --balance, minimumbalance, owner
as owner in procedure assign_owner or add in assign_owner ..... -- as before ;
deposit, mean "the owner attribute or add routine
relative to the current object". The special variable add ..... -- as before ;
Current may be used, if needed, to explicitly denote deposit (sum: INTEGER) is
this object. Thus the unqualified occurrences of add -- Deposit sum into the account
appearing in the above class are equivalent to require
Current.add. sum >= 0
In summary, this simple example shows the basic do
structuring mechanism of the language, the class. A add (sum)
class describes a data structure, accessible to clients ensure
through an official interface comprising some of the balance = old balance + sum
class features. Features are implemented as end ; -- deposit
attributes or routines; the implementation of withdraw (sum: INTEGER) is
exported features may rely on other, secret ones. -- Withdraw sum from the account
require
sum >= 0 ;
5 - Assertions sum <= balance - minimum_balance
do
It was said at the outset that classes are abstract add (-sum)
data type implementations. However an abstract ensure
data type is defined not just by a list of available balance = old balance - sum
operations, but also by the formal properties of these end ; -- withdraw
operations, which do not appear in the above may_withdraw ..... -- as before
example.
Create (initial: INTEGER) is
Eiffel indeed enables and encourages
require
programmers to express formal properties of classes
initial >= minimum_balance
by writing assertions, which may in particular
do
appear in the following positions:
balance := initial
• routine preconditions express conditions that end -- Create
must be satisfied whenever a routine is called. For
invariant
example withdrawal might only be permitted if it
balance >= minimum_balance
keeps the account's balance on or above the
end -- class ACCOUNT
minimum. Preconditions are introduced by the
keyword require. The old.., notation may be used in an ensure
clause, with a self-explanatory meaning.
• Routine postconditions, introduced by the
keyword ensure, express conditions that are The reader will have noted that a Create
guaranteed to be true on routine return (if the procedure has been added to the features of the
precondition was satisfied on entry). class. The reason is the following. Under the
previous scheme, an account was created by, say,
• Class invariants must be satisfied by objects of
accl.Create. Because of the initialization rules,
the class at all times, or more precisely after
balance is then zero and the invariant is violated. If
object creation and after any call to a routine of
a different initialization is required or, as here, an
the class. They are described in the invariant
initialization depending on a parameter supplied by
clause of the class and represent general
the client, then the class should include a procedure
consistency constraints that are imposed on all
called Create. Object creation will be obtained by
routines of the class.
writing, say
Our ACCOUNT class may be rewritten with
appropriate assertions: accl.Create (5500)
whose effect is to allocate the object (as in the
default Create) and then to execute the procedure
-89-
called Create in the class, with the given actual 6 - Generic classes
parameter. This example call is correct as the
precondition is satisfied and the invariant will hold Building software components (classes) as
after the call implementations of abstract data types yields
Note that procedure Create, when explicitly systems with a solid architecture but does not in
provided, is recognized by the compiler as special; it itself suffice to ensure reusability and extendibility.
is automatically exported and should not be included This section and the next two describe Eiffel
in the export clause. techniques for making the components as general
Assertions, as they appear in preconditions, and flexible as possible.
postconditions and invariants, should primarily be The first technique is genericity, which exists
viewed as powerful tools for documenting under different forms in Ada and CLU but is fairly
correctness arguments: they serve to make explicit new to object-oriented languages. Classes may be
the assumptions on which programmers rely when declared with generic parameters representing types.
they write program fragments that they believe are For example, the following classes are part of the
correct. In this respect, assertions are formalized basic Eiffel library:
comments. For debugging purposes, the Eiffel ARRAY [T]
environment also makes it possible to monitor LIST [T]
assertions at run-time, producing a message if an LINKED_LIST [T]
assertion is found to be violated.
They respectively describe one-dimensional
Syntactically, expressions are boolean expressions, arrays, general lists (without commitment as to a
with a few extensions (like the old notation). The specific representation) and lists in linked
semicolon (see the precondition to withdraw) is representation. All have a formal generic parameter
equivalent to an " a n d " , but permits individual T representing an arbitrary type. To actually use
identification of the components, useful for these classes, one provides actual generic
producing informative error messages at run-time. parameters, which may be either simple or class
It must be pointed out that assertions are not a types, as in the following declarations:
technique for exception handling. An exception (in
il: LIST [INTEGER];
the CLU or Ada sense) is a run-time situation which aa: ARRAY [ACCOUNT];
the programmer prefers to handle in code separate aal: LIST [[ARRAY [ACCOUNT]] --etc.
from the main flow of control, but which (for the
very reason that the program is prepared to deal An earlier article [2] discussed the rble of
with it) falls within the scope of the specification. In genericity in comparison to inheritance and
contrast, an assertion denotes a condition that should explained their combination in Eiffel, especially in
always be satisfied at the given control point; for the context of strict type checking. The solution
example, a precondition describes the requirements involves the notion of "declaration by association",
for a routine body to be applicable. Assertion not addressed here.
violation reflects a progranlming error, not an
exceptional but planned situation from which it is
7 - Multiple inheritance
possible to recover gracefully.
Eiffel offers no specific mechanism for exception
handling. In our experience, standard algorithmic Multiple inheritance is a key technique for
techniques are appropriate for dealing with reusability. The basic idea is simple: when defining
exceptional conditions. Although we accept differing a new class, it is often fruitful to introduce it by
views on the question, we considered this facility to combination and specialization of existing classes
rather than as a new entity defined from scratch.
be of secondary importance and preferred to keep it
out of the language in the interest of design A simple example is provided by the classes of
simplicity. Encouraging programmers to express the basic library mentioned above. LIST, as
correctness arguments precisely through well-placed indicated, describes lists of any representation. One
assertions appeared much more relevant. possible representation for lists with a fixed number
of elements uses an array. Such a class will be
defined by combination of LIST and ARRAY, as
follows:
-90-
class F I X E D L I S T [T] export .... To further ensure that the multiple inheritance
inherit mechanism is not misused, the invariants of all
LIST [T]; parent classes automatically apply to a newly
ARRAY [T] defined class. Thus classes may not be combined if
feature their invariants are incompatible.
... Specific features of fixed-size lists ...
end -- class FIXED_LIST
The inherit.., clause lists all the "parents" of the 8 - Polymorphism
new class (which is said to be their "heir"). Thanks
to this clause, all the features and properties of lists One important aspect of inheritance is that it
and arrays are applicable to fixed lists as well. This enables the definition of flexible program entities
simple idea makes it possible to achieve remarkable that may refer to objects of various forms at run-
economies of programming, of which we feel the time (hence the name "polymorphic").
effects daily in our experience of Eiffel software This possibility is one of the distinguishing
development. (Inheritance was introduced by Simula features of object-oriented languages. In Eiffel, it is
67. In Simula, however, as in many other object- reconciled with static typing. The underlying
oriented languages, inheritance is not multiple: language convention is simple: an assignment of the
classes may have at most one parent.) form a := b is permitted not only if a and b are of
The very power of the mechanism demands the same type, but more generally if a and b are of
adequate means to control its effects. In Eiffel, no class types A and B such that B is a descendant of
name conflict is permitted between inherited A, where the descendants of a class include itself,
features. Since such conflicts will inevitably arise in its heirs, the heirs of its heirs etc. (The inverse
practice, especially in the case of software notion is "ancestor".)
components brought in by independent developers, This corresponds to the intuitive idea that a value
the language provides a technique to remove them: of a more specialized type may be assigned to an
explicit renaming, as in entity of a less specialized type - but not the
class C export.., inherit reverse. (As an analogy, consider the fact that if I
A r e n a m e x as xl, y as yl; request vegetables, getting green vegetables is fine,
B r e n a m e x as x2, y as y2 but if I ask for green vegetables, receiving a dish
feature... specified as just "vegetables" is not acceptable, as
Here the inherit clause would be illegal without it could include, say, cauliflower.)
renaming, since the example assumes that both A What makes this possibility particularly powerful
and B have features named x and y. is the complementary facility: feature redefinition.
Renaming also serves to provide more appropriate A feature of a class may be redefined in any
feature names in heirs. In another example from the descendant class; the type of the redefined feature (if
basic library, class TREE IT] is defined by an attribute or a function) may be redefined as a
inheritance from LINKED_LIST [T] and descendant type of the original feature, and, in the
LINKABLE [T], the latter describing dements of case of a routine, its body may also be replaced by a
linked lists. The idea is that a tree is a list (as it has new one.
subtrees, to which the usual list operations of Assume for example that a class POLYGON,
insertion, change, deletion, traversal etc. apply), as describing polygons, has among its features an array
well as a list element, as it may itself be inserted as of points representing the vertices and a function
subtree into another tree. (The class definition thus perimeter returning a real result, the perimeter of
obtained is simple and compact, while covering a the current polygon, obtained by summing the
rich set of tree manipulation primitives which have successive distances between vertices. An heir of
proved sufficient in such different contexts as a POLYGON may be:
multiple-windowing screen handler and a syntax-
directed editor.) In the inheritance clause, the feature
empty of linked lists, a boolean-valued function
which determines whether a list is empty, itself
inherited from LIST, is renamed is_leaf to conform
to standard tree terminology.
-91-
This concludes the overview of the language. As o There is almost never any duplication of code.
it is well known that a programming language is in Again this was difficult to achieve with multiple
practice no better than its implementation, we inheritance and genericity: the implementation of
conclude with a brief description of the Eiffel multiple inheritance included in recent versions of
compiler and associated environment. Smalltalk [14] duplicates codes for parent classes
other than the first, precisely to avoid the graph
traversal mentioned above; most implementations
9 - The implementation of generic packages in Ada systems also duplicate
code for various generic instances of a program
The current implementation of Eiffel runs on unit. The only case in which we do duplicate code
various versions of Unix (System V, 4.2BSD, is a rather rare and special occurrence,
Xenix). It is based on translation from Eiffel to C, "repeated" inheritance with feature duplication,
then C to machine code using the resident C not described here.
compiler. It may potentially be ported to any . Memory management is handled by a ran-time
environment including a C compiler and some basic system that takes care of object creation and
operating system capabilities. (system-controlled) de-allocation. Optionally, the
Note that (as the above discussion should suffice memory management system includes its own
to show) Eiffel is in no way an extension of C; C is virtual memory subsystem, which may be turned
only used as a vehicle for implementation and has off if the facilities of the underlying operating
had no influence on the language design. Other system are sufficient. Garbage collection is also
compilation techniques would be possible, but the provided; it is performed incrementally by a
use of a portable assembly language such as C as parallel process which steals as little time as it
intermediate code has obvious advantages for can from application programs [15]. (At the
transferability of the implementation. moment garbage collection is parallel on the Unix
System V version only.)
Great care has been taken to provide efficient
compilation and execution, so that the environment ® Compilation is performed on a class-by-class
would support the development of serious software. basis, so that large systems can be changed and
The following points are particularly worth noting. extended incrementally. The translation time from
Eiffel to C is usually (in our experience) between
• As was seen above, the potential for redefinition
50% and 100% of the time for the next step,
implies that a qualified routine reference, say
translation from C to machine code.
p.perimeter, may have many different
interpretations depending on the value of p at One more property of the implementation
run-time. As mentioned, this powerful facility deserves a mention: its openness. Eiffel classes are
may result in serious inefficiencies if the search meant to be interfaced with code written in other
for the appropriate routine is made at run-time, as languages. This concern is reflected in the language
seems to be necessary. The maximum length of by the optional external clause which, in a routine
such a search grows with the depth of the declaration, lists external subprograms used by the
inheritance graph, putting reusability (which tends routine. For example, an Eiffel routine for
to promote the addition of new levels of computing square roots might rely on an external
inheritance and feature redefinition) in direct function, as follows:
conflict with efficient performance. Note that the sqrt (x: REAL, eps: REAL): REAL is
situation becomes hopeless with multiple -- Square root of x with precision eps
inheritance, as not only a linear list but a require
complete graph of ancestor classes must be x>=O ; eps>O
searched at run-time. external
The Eiffel implementation always finds the csqrt (x: REAL, eps: REAL): REAL
appropriate routine m constant time; the space n a m e "sqrt" language "C"
overhead associated with this technique is do
negligible. We found this result rather difficult to Result := csqrt (x, eps)
achieve in the presence of multiple inheritance - ensure
but essential in fight of the previous discussion. abs (Result ^ 2 - x) <= eps
Whether you have one or one million routines in end -- sqrt
your system, a.x always takes the same time.
-93-
The optional name.., subclause caters to the compiled, the system automatically looks for all
various naming conventions of other programming classes on which C depends directly or indkectly
languages. (as client or heir), and re-compiles those whose
This mechanism makes it possible to use external compiled versions have become obsolete. Unix
routines without impacting the conceptual programmers will recognize this facility as giving
consistency of the Eiffel classes. Note in particular the power of Make without programmer-written
how the C function sqrt is granted a more dignified makefiles. This is far from being a trivial problem,
status as Eiffel routine with the addition of a as the dependency relations are complex (a class
precondition and a postcondition. may be, say, a client of one of its descendants) and,
in the case of the client relation, may involve cycles.
This facility is essential in view of the design
However the solution to this problem completely
objectives listed in section 2: an environment
frees programmers from having to keep track of
promoting reusability should enable reuse of
changed modules to maintain the consistency of
software written prior to its introduction, not just of
their systems. Note that the algorithm used is able to
future software to be developed with it. Beyond this
avoid many unneeded recompilations by detecting
remark, the "external" construct lies at the basis of
that a modification made to a class has not impacted
one of the applications of Eiffel: as an integrating
its interface; this has proved very important in
mechanism for components written in other
practice, as it avoids triggering a chain reaction of
languages. An example might be scientific software:
re-compilations in a large system when the
although numerical programs will benefit just as
implementation of a feature is changed in a low-
much as others from such structuring mechanisms as
level class.
classes, multiple inheritance, geneficity, export
controls, assertions etc., programmers may prefer to The environment also contains debugging tools:
code the actual bodies of numerical routines in a tools for run-time checking of assertions; a tracer
language specifically designed for this purpose, and and symbolic debugger; a viewer for interactive
package them cleanly in Eiffel classes. exploration of the object structure at run-time.
This application is one of the three main intended A documentation tool, short, produces a summary
uses of Eiffel. The second is the most obvious, version of a class showing only its official
namely as a tool covering the whole design and information: the exported features only and, in the
implementation process; this is how we apply Eiffel case of routines, only the header, precondition and
at Interactive Software Engineering. The third may postcondition.
appeal to users who, because of external A postprocessor, ep, performs various optional
requirements, must produce final programs in some modifications on the generated C code: removal of
other language (such as Ada); it consists in unneeded routines, simplification of calls to non-
employing Eiffel as an object-oriented PDL polymotphic routines, packaging of the entire
(Program Design Language) covering the part of the generating code as a library of routines callable from
process extending from global to detailed design, other programs, "obscuring" of the C code (by
and translating the result into the required default, the generated C code is fairly readable, and
implementation language. Eiffel may even be used it is not too difficult to find the correspondence with
earlier, at the specification stage, thanks in particular the original Eiffel; "obscured" code will make it
to a facility not described in this article, deferred very hard to understand the algorithms). The last
routines. (A deferred routine has no body: two options are particularly interesting for software
implementations must be provided in descendants of implementors who use Eiffel for the development of
its class; semantics may, however, be specified by a packages that will be delivered to their customers in
precondition and a postcondition.) standard C form.
Finally the environment includes a set of basic
classes covering some of the most important data
10 - The environment structure implementations. Our goal is to extend
this library so as to cover the most common patterns
The construction of systems in Eiffel is supported of everyday programming.
by a set of development tools.
Most important are the facilities for automatic
configuration management integrated into the
compilation commands. When a class C is
-94-