This site contains older material on Eiffel. For the main Eiffel page, see http://www.eiffel.com.

On the Eiffel approach to typing

This page is taken from a Usenet message, posted in response to a discussion of typing in the context of Eiffel vs. other languages; hence the references to C++ and Smalltalk.

Introduction

Static typing helps productivity and flexibility rather than hampering them. But this assumes that typing is done properly.

C++ offers some of the typing mechanisms described below. But static typing a la C++ is too constraining for realistic software development. This is evidenced by the observation that most C++ programs use casts, that is to say, cheat with the type system.

Eiffel, in contrast, does not offer any such mechanism (it is simply not possible to bypass the type system); yet Eiffel programmers do not seem to find that typing limits their creativity in any way! So there must be something in the typing mechanism system that reconciles the safety and clarity of typing with the programmer's natural desire for power and flexibility.

What makes the Eiffel approach to typing realistic and productive is in particular the following combination of facilities.

Multiple inheritance

This is used routinely in Eiffel (as opposed to C++ where it is seen with suspicion; the difference, we think, is that the machinery of multiple and repeated inheritance has been more carefully thought out in Eiffel, making multiple inheritance a realistic tool).

Multiple inheritance makes it possible to view an object from two or more viewpoints. For example an E_MAIL_MESSAGE can be both an ASCII_DOCUMENT and a NETWORK_EXCHANGEABLE (capitalizing the name of the corresponding classes: the first will inherit from both of the next two). One of the main unvoiced reasons for the hostility to static typing in Smalltalk is that Smalltalk has only single inheritance; so in a case like this you would have to choose only one of the two viewpoints, making static typing unacceptably constraining.

Genericity

By having parameterized classes you keep the necessary flexibility for generic structures: for example class LIST [G] describes lists of any type G. If you use it as LIST [MY_TYPE] for some type MY_TYPE, the elements may be of any descendant type of MY_TYPE. C++ templates pursue a similar role.

Constrained genericity

The constrained form of genericity is essential in practice, and not present in C++. It enables you to define e.g. a class

     EXCHANGE_LIST [G -> NETWORK_EXCHANGEABLE]
meaning that if you use it as
     EXCHANGE_LIST [MY_TYPE]
then MY_TYPE must be a descendant of the type given as constraint, here NETWORK_EXCHANGEABLE. As a result you can in the body of class EXCHANGE_LIST use all the features (operations, methods) of class NETWORK_EXCHANGEABLE on objects of type G.

Assignment attempt

Assignment attempt is an operation of the form

     x ?= y
which will work in cases where normal assignment x := y may not be legal.

The assignment x := y, by the rules of typing, requires the type of y to be a descendant of the type of x. In some cases, however, you "just know" that the object denoted by y is "of the right type" even though the static declaration of y is more general than that of x. This may be the case, for example, if y denotes an object retrieved from a file, a database or a network. But you still want the assignment to be safe, in case the type of the y object at run time is NOT compatible with that of x.

Assignment attempt x ?= y achieves this: it looks at the actual object type, performs the assignment if that type is compatible with that of x, and otherwise assigns to x a void value (which you can then test for).

Assignment attempt is not used very often in a well-written object-oriented system, but when it is needed it is needed badly - without it static typing would indeed become too constraining.

Covariance

Anything declared of type T in a class can be redefined to a descendant of T in a descendant class. This is what is usually needed in practice.

Anchored declarations

An anchored declaration is of the form

     x: like y
meaning: whenever y is redeclared in a descendant class, make sure that x follows automatically. This saves a considerable amount of tedious redeclarations; it goes with the covariant policy and is not available in C++.

As a result of these mechanisms, typing in Eiffel is not a straitjacket but a help. Declaring every software entity with a type makes the software easier to read and maintain. We know of no case where typing limited anyone's creativity.

As a (not so negligible) aside, typing helps Eiffel compilers generate highly optimized code.

Finally, of course, one should never forget the main argument for static typing: the resulting increase in the safety of the software. It is good that this benefit can be obtained without damage to the programmers' creative power.