[comp.lang.eiffel] Release 2.2 overview

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.com

bertrand@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.com

bertrand@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