bertrand@eiffel.UUCP (Bertrand Meyer) (07/10/89)
This document describes the innovations brought by Release
2.2 of Eiffel.
A non-technical comment: Over the next three weeks all
current Eiffel installations will be contacted for a check
of delivery information (operating system, maintenance status
etc.).
-------------------------------------------------------------
WARNING: The paper version of this document (distributed with
the release) makes generous use of fonts. The following can
only be an approximation and some aspects may consequently be
difficult to understand.
Also, because of the 50K limit imposed by some systems,
this posting has been split into two parts. (Since we were
just over 50K, the second part is quite small.)
-------------------------------------------------------------
RELEASE 2.2 OVERVIEW
Bertrand Meyer
Jean-Marc Nerson
Interactive Software Engineering Inc.
1 OVERVIEW
Release 2.2 of Eiffel is a major set of improvements
reflecting the expanded use of Eiffel for ever more
ambitious applications.
The improvements affect the following areas.
+ Complete rewrite of the X-based Graphics Eiffel
Library.
+ Extended support for persistent objects.
+ New libraries: class browsing, parsing, lexical
analysis, non-graphical windowing.
+ Numerous improvements to the Basic Library, use of a
uniform terminology for features, better file
management facilities.
+ New tools, in particular the Eiffel Browser eb for
interactive exploration of available classes.
Improvements to existing tools such as the Eiffel
viewer.
+ Full implementation of repeated inheritance.
+ Language extensions making Eiffel more flexible:
``Unique'' values and ``Inspect'' instruction for
multi-branch choices, ``Accept'' instruction for
type-safe assignments going against the inheritance
hierarchy, support for composite objects, ``define'
clause to merge deferred and effective routines,
``obsolete'' clause to phase out library features
gently, ``indexing'' clause for systematic indexing
of reusable software components, new boolean operators.
(No change is made to existing constructs.)
+ Numerous individual improvements, performance
boosters affecting the tools of the environment as
well as the efficiency of the generated code, and bug
fixes.
+ Improved documentation, new reference manual.
Section 2 of this document covers enhancements to the
Basic Libraries. Section 3 explains the new browsing
facilities. Section 4 describes support for persistent
objects. Section 5 introduces the new language extensions.
Section 6 addresses improvements to the tools of the
environment. Section 7 lists bug fixes and areas where
performance has been improved. Section 8 presents new
documentation. Section 9 discusses compatibility issues of
compatibility with pre-2.2 versions.
2 LIBRARIES
2.1 Structure
The library is now divided into six parts (each of which
comes as a directory, with its own doc directory):
+ Kernel: classes such as ARRAY, STRING, EXCEPTIONS and
others which provide essential facilities.
+ Structures: fundamental data structures (lists,
queues, trees etc.).
+ Graphics: graphical library.
+ Winpack: non-graphical window management.
+ Parsing: lexical and syntactic analysis, compiler
writing.
+ Support: Access to internal Eiffel facilities.
In addition, a seventh directory, called 2.1, contains
a full library functionally equivalent to the previous (2.1)
library, enabling previously written Eiffel systems to be
compiled and run exactly as before. Minor adaptations may be
needed for these applications to work under the new
libraries (see section 9 on compatibility issues).
2.2 Graphics
The graphics library has been entirely rewritten to use X
Windows version 11.3. Many more facilities are provided than
with the 2.1 version; in general, the graphics library is
now at the same level of robustness as the rest of the
environment.
The X dependencies are isolated in specific classes to
facilitate future adaptations of the library to other
graphical bases.
The X-based tools work much better than in the past
with the rest of the X system; in particular, they work
across a network (with a client-server architecture) and
with any display manager.
Several graphical demonstration systems are provided in
source form to serve as models for use of the library. They
include the GOOD graphical browser (see below), which has
been considerably improved with new facilities, a better
interface, mouse tracking for moving class bubbles etc.
A set of C routines interfacing Eiffel and X has been
included in the Eiffel delivery to help cross-developing
portable X-based applications.
The MIT X Windows package itself is not included in the
delivery any more, as it is expected that a majority of
installations will have independent access to X. The
graphics library and tools require that X version 11.3 be
installed.
2.3 Support
The ``support'' library includes facilities for persistent
objects (ENVIRONMENT, STORABLE, see below), access to the
internal structure of Eiffel objects (INTERNAL), advanced
memory management (MEMORY) and browsing (E_CLASS, E_WORLD,
see below).
Class MEMORY now includes a procedure dispose with no
argument and an empty body. This procedure is invoked by the
garbage collector (if enabled) when it reclaims an object. A
programmer wishing to have a particular action executed
whenever an instance of a certain class is reclaimed (for
example, if the object was associated with a file, closing
that file) may write the class as a descendant of MEMORY and
redefine dispose appropriately.
Class EXCEPTIONS (a support class, but included in the
kernel library for technical reasons) now includes a
procedure continue. By inheriting from this class and
redefining the procedure, a class design may ensure that
processing can continue at the point of interrupt (after
designated handling) for certain exceptions.
2.4 New libraries
Two new libraries are provided.
The parsing library provides a set of predefined
classes for object-oriented parsing, with the supporting
tools for lexical analysis. The parsing classes make it
possible to write parser-based tools (compilers,
interpreters, static analyzers and the like) with a natural
and modular structure, based on classes which correspond to
grammar productions. Semantics can be added easily using
multiple inheritance.
The winpack library supports the development of
window-oriented applications on character-oriented (rather
than graphical) terminals. It is enough for the terminal to
have the proper ``termcap'' descriptions. The facilities
supported include hierarchically nested windows, cursor
movement, echoed and non-echoed input in ``raw'' and
``cooked mode'', text manipulation in windows and many
others. The basic class is WINDOW. An heir of this class,
called EDITOR, provides the functionality of a simple
window-oriented text editor.
2.5 Data structure library
The data structure library has been extended with new
abstractions such as chains, ordered sets, priority queues
etc.
The FILE class (now part of the kernel library) has
been extended with new input-output facilities and better
handling of erroneous cases.
2.6 Terminology and consistency
A systematic effort has been undertaken to use a consistent
terminology throughout the data structure and other
libraries.
For example, the basic operation for inserting an
element into a data structure is called put, replacing enter
(for arrays), push (for stacks), add (for queues), insert
(for hash tables) etc. The basic operation for accessing an
element is called item, replacing entry (arrays), top
(stacks), oldest (queues) etc. The signatures (types of
arguments and results) are not the same in all cases, but
the name is the same if the purpose is similar.
The old names are still available as ``obsolete''
features (see below).
The consistency of the library has also been improved
in other ways, particularly by introducing more deferred
classes to capture common properties, by including more
assertions, and by adding new generic parameters to certain
classes to make them more general.
As an example of the last case, the old H_TABLE [T]
class described hash tables; the keys used to insert and
retrieve elements had to be character strings. This may be
too restrictive. Consequently, the new class HTABLE [T, U
-> HASHABLE] uses a generic parameter U representing the
type of the keys. U is only constrained to be a descendant
HASHABLE, a deferred class which includes a hash deferred
function to be used for hashing keys. STRING, of course,
inherits from HASHABLE.
The new old H_TABLE, kept for compatibility, has been
adapted so that it now inherits from HTABLE [T, STRING].
2.7 ANY and HERE
Two new kernel classes, ANY and HERE, offer universal
facilities which are automatically made available to every
class.
These classes play a special role, as any programmer-
defined class now inherits from HERE; HERE is itself an heir
to ANY.
ANY includes routines which are potentially useful for
any class:
+ The string-valued function out is such that a.out,
for any a, contains a printable representation of a
(which may be an object or a value of a basic type).
+ The procedure copy is such that a.copy (b) copies the
contents of the object associated with b onto the
object associated with a. Both objects must exist
(otherwise an exception is raised). Procedure copy
is similar to the predefined feature Clone, but its
target is an existing object rather than one created
for the occasion.
+ Routines deep_copy and deep_equal provide for
recursive copy and recursive equality test of complex
structures.
Class HERE, as delivered, is empty except for its
``inherit ANY'' clause. It is meant for defining universal
facilities that are considered useful by a certain
programmer, a certain group or a certain company. In
contrast, ANY should normally be kept unchanged.
3 BROWSING
An important set of new facilities allows for browsing, or
exploration of existing classes and their properties.
These facilities are all implemented in terms of the
features of the support library class E_CLASS and a few
related classes. This means that any Eiffel application may
query the environment about classes and their properties by
accessing the features of these classes.
An instance of E_CLASS describes an Eiffel class and
gives access to its features selected according to various
criteria (attributes, routines, functions, deferred routines
etc.), its parents and ancestors, heirs and descendants,
clients, suppliers, invariant and so on.
Two interactive tools give users access to these
facilities. One is eb (Eiffel Browser), which will work on
any character-oriented terminal. The other is GOOD, which
runs on X Windows, is mouse-driven and provides the same
information in graphical form (bubbles and arrows). GOOD
(the acronym means ``Graphics for Object-Oriented Design'')
also supports further facilities for creating new classes
through graphical interaction.
Both eb and GOOD are delivered in source form. This
provides Eiffel programmers with complete examples of
advanced use of the class browsing facilites from class
E_CLASS.
4 PERSISTENCE
In pre-2.2, persistence was supported by class STORABLE and
its two routines store and retrieve. The former would store
an object and all its dependents (the objects to which it
contains references, directly or indirectly); the latter
would retrieve the whole thing.
These facilities continue to be supported. More
advanced techniques are now available, however, through the
support class ENVIRONMENT. An environment (instance of class
ENVIRONMENT) is a set of objects. At any time during
execution, one environment is active; the active environment
may be changed. Every object, as it is created, becomes
part of the currently active environment. Furthermore, some
objects may be given keys with respect to the environment
they belong to. A key is a string.
An environment may be stored into a file; this means
that all the objects of the environment, and their
dependents, are also stored. The environment may then (in
the same or another session) be loaded back. Then
individual objects of the environment may be selectively
retrieved if they have been given keys.
An environment is stored either explicitly (by
env.store (f)) or by executing at initialization time one of
the calls env.store_on_end (f) or env.store_on_failure (f),
which specify that the entire environment should be stored
automatically when the program terminates normally or
abnormally.
These facilities represent a first step towards
including within Eiffel a full-fledged object-oriented
database system, and for removing the conceptual distinction
between those objects which are in main memory and those
that reside elsewhere (possibly coming from environments
stored in previous sessions), in the spirit of virtual
memory.
5 LANGUAGE EXTENSIONS
5.1 Expanded types
Expanded types provide a more flexible dynamic object model,
where objects can have sub-objects, not just as references
to other objects.
An entity may now be defined as being of an
``expanded'' type, meaning that its value will be an object,
not a reference to possible objects. This makes it possible
to avoid unneeded indirections and provides a uniform
framework for describing class types and basic types
(INTEGER etc.). Another advantage is the ability to share
information with external languages such as C in a more
flexible way.
As a consequence of the more flexible dynamic model, a
DOUBLE expanded type (double precision reals) is now
supported.
A new set of predefined types is introduced: BITS M,
for any non-negative integer constant M, describes objects
whose value fits in M bits. All class types (for which
entities represent references) fit in 32 bits; so do INTEGER
and REAL. DOUBLE fits in 64 bits.
Associated techniques extend the generic facilities.
They are described in a separate document.
These extensions make the Eiffel type system at the
same time more consistent, more powerful and more flexible.
5.2 Infix and prefix operators
A routine can now be defined in such a way that calls to the
routine will use an operator in prefix or infix form.
For example, an addition routine in a class MATRIX can
be named infix "+", so that calls will be of the form a + b.
Previously, the routine would have been named for example
plus, with calls of the form a.plus (b)
As an example, class COMPARABLE from the kernel library
now contains the following declaration:
infix "<=" (other: like Current): BOOLEAN is
-- Is current element less than or equal to other?
deferred
end; -- "<="
Only the predefined operators of the Eiffel grammar
(arithmetic, boolean and relational operators) can be used
in infix or prefix form. They are the following:
+ - * / < > <= >=
and or xor not
div mod
Of these, only +, - and not may be used as prefix. All
except not may be used as infix. The precedence of all
these operators is fixed, and remains as given in the
grammar for pre-2.2 Eiffel (where they were applicable to
operands of basic types only).
A routine declared in infix or prefix form is like a
normal routine whose name, instead of being an identifier,
would be of the form infix "operator". This name may appear
wherever a routine name is legal, for example in the routine
definition itself (as for "<=" in the above declaration), in
a rename clause (such as rename union as infix "+", infix
"<" as smaller), an export list or a redefinition clause.
For routine calls, however, the syntax uses the infix or
prefix form of the operator instead of the usual
target.routine_name (...) form.
The infix-prefix mechanism is only a syntactic
facility. It should help produce programs that are both
nicer to write and nicer to read.
5.3 Repeat clause for export lists
The ``repeat'' clause makes it easier to write and manage
export clauses. It is applicable to cases when the exports
of a class include all the exports of one (or more) of its
parents.
According to the Eiffel rules on inheritance and
information hiding, a class B that inherits from a class A
is not constrained to export all the features exported by A.
When this is the case, however, the repeat subclause
provides a convenient syntactical abbreviation. The presence
of
repeat A
in the export clause of B has the same meaning as a textual
copy of the export clause of A. For example, here is the
beginning of class FIXED_STACK in the structure library:
-- Stacks with a fixed physical size, implemented as arrays.
class FIXED_STACK [T] export
repeat STACK, max_size
inherit
STACK [T]
define
empty, nb_item
ARRAY [T]
rename ...
redefine ...
Here FIXED_STACK exports all the features that are
exported by its parent STACK. Additionally, it exports
feature max_size.
A repeat A subclause appearing in the export clause of
B is only permitted if B is an heir (not an indirect
descendant) of A. Its is equivalent to a list of features,
some with export restrictions, copied from the parent. The
export clause of the heir may include other elements, as
with max_size in the above example. In the case of multiple
inheritance, there may be more than one repeat subclause.
The advantage of the ``repeat'' facility is not only
that export lists are shorter but also that any change in
the export list of the parent will be automatically
propagated to the heir. This brings an important
simplification to the management of export lists.
5.4 Define subclause
The new define subclause, part of the inherit clause, makes
it possible to implement one or more deferred routines by
merging them with an effective (non-deferred) routine or
attribute.
As an example, both the ARRAY kernel library class and
the LIST structure library class include an integer function
called nb_items, giving the number of items in an array or
list. This function is is effective in ARRAY, where it
returns upper - lower + 1 (it could also have been
implemented as an attribute); it is deferred in LIST. The
former provides the appropriate implementation for the
latter in class FIXED_LIST (lists with a fixed number of
items, implemented as arrays), which begins as follows:
class FIXED_LIST [T] export
repeat LIST
inherit
LIST [T]
redefine ...
define
nb_items
ARRAY [T]
rename ...
In pre-2.2, the same effect would have been achieved as
follows:
class FIXED_LIST [T] export
...
inherit
LIST [T]
redefine ...
ARRAY [T]
rename nb_items as array_nb_items, ...
-- Renaming is necessary to avoid a name clash
feature
nb_items: INTEGER is
-- Number of meaningful items in list
do
Result := array_nb_items
end; -- nb_items
...
The improvement in ease of expression is significant:
it is no longer necessary to include a trivial function
definition; nor is the renaming of nb_items for arrays
needed any more, since the name clash in this case is in
fact desired. There is also a performance improvement, since
nb_items for FIXED_LIST is now the same code as the
corresponding function for ARRAY, avoiding an extra level of
routine calls.
The rest of this section describes the precise syntax
and semantics of the define clause. For the semantics, it
is useful to introduce the notion of ``final name'' of a
routine The final name of a routine in a class is the
routine name if the routine is introduced in that class, or
inherited from a parent and not renamed. If the routine is
inherited under a new name, the final name is that name.
The define subclause may appear in one of the inherit
clauses of a class C after the redefine subclause, if any,
and before the rename subclause, if any. The keyword define
must be followed by a list of final routine names, all of
which are inherited deferred routines. For each such routine
r, there must be an effective feature (routine or attribute)
in C, with the same final name and the same signature as r.
This effective feature may be either declared in C or
inherited from a parent; it serves as implementation of r in
C. (Hence r is effective in C.)
If two or more of the features of C have the same final
name, then C would have been illegal in pre-2.2 because of
the name clash. In 2.2, however, if all of these routines
are deferred except at most one, the deferred ones all
appear in define subclauses, and the conditions for their
correct implementation by an effective feature are met, then
no illegal name clash will now be diagnosed.
In the simplest case, C inherits only one deferred
routine called r from its parents, and provides an effective
definition for r:
class C export ... inherit
inherit
P
define r
feature
r is
-- The effective implementation
do ... end; -- r
...
This is the standard case of providing an effective
declaration for an inherited deferred routine. Here the
inclusion of r in the define subclause for P is optional.
This is compatible with pre-2.2 Eiffel.
The define subclause is particularly useful when, in a
multiple inheritance case, a class implements a deferred
routine inherited from a parent by an effective routine
inherited from another. Assume C inherits from A and B, and
we want to implement r, a deferred routine inherited from A,
by an effective feature inherited from B. If the names are
the same (as in the nb_items example), it suffices to list r
in the define subclause for A:
class C export ... inherit
A
define r
...;
B
...
The define facility can also be used, however, if the
name of the defining effective feature is different, say s.
What is required, as seen above, is that the final names
should be the same. This may be achieved by renaming either
the effective or the deferred routine. For example:
class C export ... inherit
A
define r
...;
B
rename s as r
...
The define subclause simplifies a number of cases of
multiple inheritance and has been fruitfully applied to the
libraries.
5.5 Accept instruction
The Accept predefined feature makes it possible to perform
assignments going against the static inheritance rules if
the assignments are type-safe at run time.
The instruction is written as follows:
x.Accept (y)
where x is an entity and y is an expression, and is
syntactically correct if and only if the static type of x,
say D, conforms to the static type of y, say A. (The static
type is the type with which an element is declared; a type
conforms to another if it is one of its descendants, with
special provisions for inheritance.)
In this case, the type rules of the language permit the
assignment y := x, but not the reverse one. Accept makes
the reverse assignment possible, but only when it is
dynamically found to be compatible with the type system. In
other cases, the value of x will become a void reference.
The effect of the instruction may be defined by the
following pseudo-Eiffel extract:
if
not y.Void
and then ``The type of the object associated with y conforms to A''
then
``x := y''
-- This assignment cannot be written as such
-- since it violates the type rules.
else
x.Forget
end
In other words, the instruction assigns to x a
reference to the object referred to by y if this object
exists (not y.Void) and its type is a descendant of the type
of x; otherwise, it makes x a void reference. In contrast
with := assignment, whose validity is determined at
compile-time by examining the static type of the source and
target, the validity of the Accept instruction depends on
the dynamic type of the source (that is to say, the type of
the associated object).
This form of controlled reverse assignment is
essentially useful in connection with generic structures and
persistence. Assume that RECTANGLE inherits from POLYGON;
the former class introduces a new feature diagonal. Assume
that during your last session before your one-year around-
the-globe sailing trip you ran an execution of a system
containing the entity
pstack: LINKED_STACK [POLYGON]
and pushed a number of polygons onto it by calls of the form
pstack.put (p). (Feature put is the ``push'' operation for
stacks). Because of the basic type rules, some of these p
may actually have been of type RECTANGLE.
Before you left you stored away the pstack structure in
a file, using the persistence facilities described in
section 4. As you come back you use the associated
facilities to retrieve this stack. Its top stack may be
obtained through:
p := pstack.item
where item is the feature from LINKED_STACK which returns
the top of a stack.
Assume now that you remember (or think you remember)
that the last object you pushed on the stack before you took
off was actually a rectangle and you absolutely need to
obtain the diagonal of that rectangle. Unfortunately, the
type of pstack is LINKED_STACK [POLYGON], so that item here
returns a result of type POLYGON. Then entity p as used in
the above assignment, must also be of this type (or an
ancestor) and the call p.diagonal would be illegal.
The Accept facility may be usefully applied in such a
case:
pstack: LINKED_STACK [POLYGON];
p: POLYGON;
r: RECTANGLE;
rdiag: REAL;
...
p := pstack.item;
r.Accept (p);
if not r.Void then
rdiag := r.diagonal
else
-- p was void, or else not a rectangle
... Appropriate treatment ..
end
This technique is safe: if your memory failed you and
the stack top is not in fact a RECTANGLE object, no
incorrect application of diagonal may result.
Most uses of the Accept facility should be structured
in this fashion, with a conditional instruction after the
Accept to check if the target has indeed been assigned a
proper reference.
In short, the Accept instruction supports assignments
for cases in which the static inheritance rules would not
permit normal assignment but the dynamic type of the source
object make the operation meaningful. The operation is safe
(no incorrect conversion may result); the programmer can
control it by testing for voidness.
The instruction provides a way to test for the dynamic
type of an object. Usually, however, there is no need to do
so in standard cases of Eiffel programming; the implicit
form of testing provided by dynamic binding is much
prefereable to explicit testing, as explained in detail in
Object-Oriented Software Construction. Accept does provide a
useful complementary mechanism in cases when one does need
to find out the dynamic type. Usually this should only arise
in the context of object persistence, as in the above
example: when objects are retrieved from a previous
execution of an Eiffel system, the type information
contained in the source text of that system has been lost.
5.6 Unique values
A new form of constant integer attribute, declared as
``unique'', is provided. This makes it possible to let the
compiler devise a set of integer codes that are guaranteed
to be different and may then be used in multi-branch choice
instructions.
The form of a ``unique'' declaration is:
a, b, c, ...: INTEGER is unique
The effect of such a declaration is the same as the
effect of
a: INTEGER is V1;
b: INTEGER is V1;
c: INTEGER is V1;
...
where V1, V2, V3, ... are different integer constants. The
difference, however, is that the values of these constants
are chosen by the compiler, not the programmer. They are
guaranteed to be different for all ``unique'' attributes
introduced within a class. The uniqueness is not guaranteed
across classes; in particular, a unique attribute introduced
in a class may have the same value as a unique attribute
inherited from an ancestor of that class.
This facility relieves the programmer from having to
assign integer codes manually when there is a fixed list of
possible situations. In other words, the declaration
everest, mont_blanc, mc_kinley: INTEGER is unique;
replaces the more tedious:
everest: INTEGER is 1;
mont_blanc: INTEGER is 2;
mc_kinley: INTEGER is 3;
Corresponding multi-branch tests may then be made using
the inspect instruction, as seen next.
5.7 Inspect instruction
The inspect instruction is a new control structure for
multi-branch choices, avoiding more complicated if... then
with a fixed set of choices and is not a substitute for
inheritance and dynamic binding.
The syntax of the construct is:
inspect
e
when V11, V12, ... then
instructions
when V21, V22, ... then
instructions
...
when Vn1, Vn2, ... then
instructions
else
instructions
end
Here e is an expression of type INTEGER or CHARACTER;
V11, V21, ..., V21, etc., called ``inspect constants'', are
constants of the same type as e; instructions represents a
sequence of zero or more instruction separated by
semicolons. The else instructions part is optional.
The inspect constants may be explicit constant values
or constant attributes; in the latter case they may have
been declared as ``unique'', and must all have been
introduced in the same class, so as to be guaranteed to have
different values. (If any is declared as ``unique'', then
all must be.) If they are not ``unique'', their values must
also be all different.
For inspect constants declared explicitly (not
``unique''), a notational facility is offered: a sequence of
consecutive explicit values, such as 3, 4, 5 or 'a', 'b',
'c', 'd' may be abbreviated as an interval, written in the
form min..max, as in
3..5
'a'..'d'
If, when e is evaluated, its value is one of the Vij
constants in one of the when clauses, then the effect of the
inspect instruction is to execute the corresponding
instructions right-hand side. (The rules ensure that there
is at most one such when clause.) If no when value matches
the value of e, then the else clause is executed if present;
otherwise an exception is raised. The symbolic name for the
corresponding exception code in the library class EXCEPTIONS
is Invalid_inspect_value.
The inspect instruction provides support for multi-
branch discrimination for a fixed set of choices. Like
traditional ``case'' instructions, however, it is a closed
construct: adding new cases may require important
modification in client code (see the ``open-closed
principle'' in Object-Oriented Software Construction,
section 2.3). Any situation in which some non-trivial
operations must be performed as a result of the
discrimination, or new cases are expected to arise, should
be handled not by writing multi-branch choices but by using
specific object-oriented techniques: writing a set of
classes that inherit from a common ancestor and redefining
in each of these classes the routine performing the variable
operation. Then, thanks to dynamic binding, the call a.r
will select the appropriate version based on the run-time
form of a. The inspect mechanism is not appropriate for such
situations.
5.8 Obsolete routines
The ``obsolete'' facility provides a way to phase out
routines from a library class without immediate impact on
current users.
A clause of the form obsolete Message may be added
before the is in the declaration of the routine. The message
is a string constant in quotes.
As an example, it was noted above that the procedure
for changing an array entry is now called put rather than
enter. Existing classes, however, will still use the old
name. This name is available as an obsolete feature name in
the new version of library class ARRAY:
enter (i: V; v: T) obsolete "Use ``put (v, i)''" is
do
put (v, i)
end; -- enter
This declaration actually appears not in ARRAY, but in
one of its parent, the kernel class INDEXABLE [T].
The message should indicate the suggested replacement.
Often it should just be of the form Use "new_name" instead;
in cases such as the above, it also indicates that the order
of arguments has changed.
A routine declared as obsolete has all the properties
of a normal routine with two exceptions:
+ Obsolete routines never show up in the output of the
short class abstracter.
+ When the compiler (commands es or ec) detects that a
client or descendant of a class C uses an obsolete
feature of C, it produces a compile-time warning of
the form ``Feature name is obsolete; Message'', where
Message is the message defined for the obsolete
routine.
Warnings can be disabled through the -w option of
either compiling command.
Only a routine can be obsolete, not an attribute. This
is because the presence or absence of an attribute affects
the run-time structure of every instance of the class. To
obtain the same effect as if attributes could be made
obsolete, do the following on an attribute a introduced in
class C:
+ Choose a fresh attribute name, say obsolete_a, not
used for any feature in C.
+ Replace all occurrences of the name a in C by
obsolete_a.
+ Declare in C a new argumentless function called a,
with a result of the same type as obsolete_a. The
body of this function is just Result := obsolete_a.
Declare this function as obsolete.
+ The interface of C is not changed; nor is the run-
time structure of its instances. Clients and
descendants are still valid. There is a performance
cost, however, since outside accesses to a now imply
a function call.
Thanks to the ``obsolete'' facility, libraries can be
refined and improved without undue immediate impact on
programmers. Without this facility, the effort applied to
the Basic Eiffel Library, in particular the revamping of
feature names (section 2.6 above), would not have been
possible. In the Basic Library, the ``obsolete'' features
will be removed from any version distributed ten months or
more after the features first became obsolete.
5.9 The ``indexing'' clause
The ``indexing'' clause is meant to help archiving classes,
retrieving them and browsing through them.
This is a new optional clause, which may be included at
the beginning of a class. Its syntax is illustrated by the
following example:
indexing
author: Jane_Smith;
keywords: hash, hashing, table, searching;
date: March, 1989;
revision_1: July, 1989
class HTABLE [T] export
... (etc.)
The labels (such as ``author'') are identifiers; the
right-hand side are elementary items (integers, identifiers
etc.) separated by commas.
The purpose of this facility (remotely inspired by the
Cobol ``identification division'') is clear: allow for
indexing of reusable software components by sophisticated
programming environment tools such as indexers and browsers.
Although, in the Eiffel tradition, most of the documentation
about a class is in the standard class text itself, some
extra information may be useful. The ``indexing'' clause
will contain this information.
For release 2.2, the tools of the Eiffel environment do
not take much advantage of this facility. It has been
included as a way to prepare for future enhancements, which
will be particularly useful as the body of Eiffel classes
available from various sources grows, paving the way for a
full-grown industry of reusable software components.
5.10 New boolean operators
Two new boolean operators are available: xor, for exclusive
or, and implies. The definition of implies is that a implies
b is the same as
not a or else b
This operator is especially useful in class invariants
and other assertions. Numerous invariant clauses of the data
structure library which used an or or or else form have been
rewritten more elegantly using implies.
5.11 Interface with external routines
The interface between Eiffel and other languages, especially
C, has been made more flexible in several ways.
The presence of expanded types makes it possible to
exchange structures, not just one-word items, with other
languages.
An external routine can be called with the address of
an Eiffel routine r as actual argument. The argument is
written @r. The external routine (which may for example be a
call-back mechanism) may then call r.
Other facilities are provided for a C routine to call
Eiffel routines and create Eiffel objects.
6 ENVIRONMENT TOOLS
A number of significant improvements have been made to
existing tools.
6.1 Compiler (es, ec)
The compiling commands es and ec have been improved in a
number of ways. This section addresses the functional
improvements; performance improvements are discussed below.
There is no limitation on the number of classes of a
system. (A given run of es or ec, however, can compile at
most 500 new classes, which should not be a problem in
practice.)
Command ec will now read all its options in the System
Description File (which must be called .eiffel in the
current directory) if there is one. Any command-line option
overrides the corresponding SDF option.
Command ec has a new option: -gi (i = 1, 2, 3 or 4).
The effect is to stop after pass i of the compiler.
By default, the compiler assumes that the kernel
library is in a directory fixed at installation time. This
can be overridden by specifying another directory in the new
KERNEL entry of the SDF, or, for ec, through the -k
command-line option.
The SDF entry listing directories for needed classes is
now labeled UNIVERSE rather than SOURCE (the latter name
still works).
Both es and ec now have a -w option which suppresses
printing of compile-time warning messages. A LINKER
environment variable is now available, corresponding to the
linker to be used by es when option -l is selected.
6.2 Run-time behavior
Two changes have been made to the run-time behavior of
compiled systems.
The first change applies to the effect of a particular
exception. Normally, when an exception occuring at run time
is not explicitly caught by a rescue clause of some routine
or class, a complete ``exception history table'' is
displayed (on the standard output), showing a log of all
exceptions having occurred during the execution of the
system. This useful facility can be a nuisance in cases when
the exception was simply caused by the user typing the BREAK
character (control-C) to stop execution. This case is now
recognized and leads to silent termination, without any
exception history table being produced. Of course, the
corresponding exception can still be caught explicitly by
the software.
The other change applies to the effect of the TRACE
debugging option for step-by-step execution tracing. For
classes compiled with this option on, the trace now
indicates at each line the number of the call's source line
in the corresponding class.
6.3 Short and flat
Command short, the class abstracter and documenter, has two
new options: -i, to produce an index, and -a.
Option -i produces an index of all classes processed by
short and all the exported features of these classes; troff
will include the proper page numbers. This has been used to
provide the library manual with a comprehensive index.
Option -a, which is also applicable to the inheritance
flattener flat, prints exported features inherited from
class ANY (the default is not to print them since they are
in all classes).
If a repeat clause is present in a class (section 5.3),
short will attempt to expand it; this requires that the
class have been at least partially compiled. If not, short
will keep the repeat clause unchanged.
The command has been updated to ignore ``obsolete''
features (section 5.8).
6.4 The viewer
The viewer is a run-time object inspector which quadruples
as interactive debugger, fake Eiffel interpreter and
interactive tester.
A number of facilities have been added to the viewer;
in particular:
+ Routines called interactively can have references (of
class types) as arguments; assignments to references
are also possible.
+ The objects encountered during a viewer session are
remembered and can be given human-significant names.
+ Input and output can be freely redirected.
6.5 C package generation
The postprocessor is the part of the compiler used to
produce self-contained C packages for cross-development and
to perform in-depth optimizations.
In pre-2.2, different C packages produced from
different Eiffel systems could not coexist without some
tedious and non-trivial hand adaptations. It is now
possible to generate a package which includes an external
archive resulting from a previously produced C package.
7 BUG FIXES
7.1 Repeated inheritance
Repeated inheritance occurs when a class inherits more than
once from the same ancestor. This is often a consequence of
multiple inheritance (D inherits from B and C, both of which
inherit directly or indirectly from A.)
The rules for repeated inheritance are described in
section 11.6 of Object-Oriented Software Construction; they
imply that features (routines and attributes) which are
inherited more than once are duplicated or shared depending
on whether they have been renamed or not.
In version 2.1, the rules had been implemented for
routines but not yet for attributes. The full repeated
inheritance rules are now supported.
7.2 Performance
The performance of the tools has been improved in a number
of areas.
The efficiency of the run-time system has been
significantly improved in both time and space. The tables it
uses have a much smaller size, especially in the case of
large systems. The code has also been made more compact. The
run-time has been split into a number of pieces; only the
needed pieces are actually loaded, depending on the options
selected (for example garbage collection or not).
The startup time for es, especially for large systems,
has been significantly decreased (by a factor of two or
more).
Code generated with option NO_ASSERTION_CHECK on is
more compact and has a shorter startup time.
The inheritance flattener flat is about twice faster.
The low-level routines used for input and output in
class FILE are significantly faster. In general, the
performance of input and output primitives from this class
is considerably better thanks to the memorization of more
file information.
When compiled under NO_ASSERTION and OPTIMIZE, the
postprocessor uses an internal compilation option which
removes useless data, reducing the size of executable files.
7.3 Miscellaneous
A number of problems have been corrected.
The use of a reserved word as identifier produces a
much clearer error message.
Using Result in a procedure causes an error message.
A remote call of the form a.b....Clone (...), with more
than one dot, causes an error message. (As with Create, this
violates export restrictions; the supplier should include an
exported procedure that performs the cloning.)
The violation of a precondition triggers an exception
in the caller, not the called routine (in accordance with
the ``programming as contracting'' philosophy).
The types of external routines arguments can be
declared, in accordance with the syntax given in Object-
Oriented Software Construction.
The inheritance flattener flat keeps comments coming
right after an attribute (this is particularly useful if
short is applied to the result) and class invariants.
A bug regarding the use of the C_COMPILER environment
variable has been fixed.
The -e (explain) option for es and ec prints out
information on calls to cc (C compiler).
Commands es and ec do not fail any more in the case of
deep relative paths between the current directory and other
needed directories.
Cycles in the inheritance graph are detected in all
cases.
The exception history table contains adequate
information when the post-processor (C package cross-
generator and optimizer) is used, and when repeated
inheritance is used with routine duplication.
The postconditions of some routines in the data
structure library classes FIXED_QUEUE and LINKED_QUEUE have
been corrected.
Bugs in data structure library classes H_TABLE and
BOOLEAN_SET have been corrected.
A rare but annoying bug in the garbage collector
(occurring for routines creating many objects and using
expressions referring to objects returned by functions) has
been corrected.
Exceptions occurring during the processing of an
exception are caught properly and cause immediate
termination, with a clear trace history being printed if
possible.
Tools es and ec are fully consistent with each other.
An extra semicolon after the last parent declaration in
an inherit clause is now harmless.
Constrained genericity works better in some complicated
cases.
The screen-oriented tools such as the viewer and eb now
understand padding in Termcap entries and have better error
recovery when the TERM and TERMCAP environment variables are
not properly set.
END OF PART 1 (OF 2)
--
-- Bertrand Meyer
bertrand@eiffel.combertrand@eiffel.UUCP (Bertrand Meyer) (07/10/89)
PART 2 (OF 2)
-------------------------------------------
8 DOCUMENTATION
The existing documentation (User's Manual, Library Manual)
has been comprehensively updated.
A new manual, entitled Eiffel Reference Manual,
provides a complete reference on Eiffel as a language. This
manual is a first draft and is still subject to extension
and refinement.
Each library comes with an on-line doc directory
containing explanations and examples. As noted above, the
graphical library and the browsing facilities are delivered
with full-fledged example applications in source form.
9 COMPATIBILITY ISSUES
Every effort has been made to ensure that previously correct
software would still compile and work exactly as before.
Minor problems may, however, arise in two areas: reserved
words and feature terminology in the data structure library.
2.2 introduces the following new reserved words:
Accept
BITS
define
DOUBLE
expanded
implies
indexing
infix
inspect
obsolete
prefix
unique
when
xor
Any use of these words as identifier in an existing
class will raise an error. This will be corrected by
choosing other identifiers.
In the data structure library new identifiers have been
introduced for many library features. All the old ones,
however, have been kept as ``obsolete'' features. This
fully protects all client classes against any
incompatibility; the only practical consequences are
compile-time warnings (5.8) that the end of the world is
near unless clients mend their ways.
To a large extent, descendants are safe too. In some
cases, however, classes that used to be correct will produce
compile-time errors because they inherit from two library
classes with identically named features, raising a name
clash. The likelihood of such an event is increased by the
unification of feature terminology (2.6), which implies that
many library classes have features using a small number of
universal names such as put and item.
Such problems will be resolved in a straightforward way
by adding adequate rename clauses in the descendant classes
raising the clashes. The effort involved should be minimal.
Programmers who do not want to make this effort
immediately may ensure full library compatibility by
specifying the ``2.1'' library directory in the UNIVERSE (or
SOURCE) entry of the System Description File. This way old
software will compile exactly as before. It is of course
advisable to migrate as soon as possible to the new
libraries.
--
-- Bertrand Meyer
bertrand@eiffel.combertrand@eiffel.UUCP (Bertrand Meyer) (07/14/89)
The following keyword was omitted from the list of new 2.2 reserved
words in section 9 of the article ``Release 2.2 Overview''
(second part, <172@eiffel.UUCP>):
repeat
This is used in the export clause of a class to include an entire
parent's export clause, as described in section 5.3
(first part, <171@eiffel.UUCP>).
Thanks to Eugene Rodolphe
(uunet!ucsd!ames!hc!lanl.gov!cmcl2!esquire!info5!eugene)
for pointing out the omission.
-- Bertrand Meyer
bertrand@eiffel.com