|
||||
On the Eiffel approach to typingThis 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. IntroductionStatic 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 inheritanceThis 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 genericityThe 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 attemptAssignment attempt is an operation of the form x ?= ywhich 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 declarationsAn anchored declaration is of the form x: like ymeaning: 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.
|