At long last, ISE Eiffel has released their development environment and libraries as Open-Source software, as announced in their press release (ISE Eiffel). The project is hosted on a wiki at the ETH and includes downloads for the most recent builds and nightlies (for Linux and Windows). The ISE implementation is the only one that fully supports the ECMA-367 standard, released in June of 2005. The download includes all development tools and libraries.
This is the language that Java and C# should be chasing instead of just trying to be better than one another or C++. Their recent introduction of generics[1] as glorified preprocessors, in which generic classes don’t follow expected inheritance rules, is one such recent debacle. Eiffel is the one OO language that asks the question, “how can we make the language more expressive?” before asking “how can we make the compiler easier to write?”
Eiffel the language has several features that it is relatively safe to say neither Java nor C# will ever have:
expanded
and the naturally expanded types, like INTEGER
, BOOLEAN
, FLOAT
and so on are simply optimized by the compiler. The magic happens in the compiler, though, allowing developers to inspect, use and design with INTEGER
s in the same way that they design with LIST
s, WINDOW
s or other compound or reference types.The generics recently included in Java and C# are a great improvment over the 1970s-style arrays previously available. They allow a much higher level of expressivenes and, most importantly, obviate a lot of iteration code and horrible, horrible casting. However, seemingly innocent limitations—like a lack of parameter covariance and lack of inheritance—cripple these implementations further.[4] Now that both C# and Java have some form of generics, we need to change the following clever tagline[5] from:
“OOP without generics is like a car that only turns left—sure you can go right, just do three lefts.”
to:
“OOP without parameter covariance is like a car that only turns left—sure you can go right, just do three lefts.[6]”
Because of this, the class models in Java and C# will also never offer another wicked feature of Eiffel, anchored types.[7]
Eiffel has many excellent online presentations illustrating Design-by-Contract and comparing itself to Java, C# and Delphi Pascal. They’re well worth a look.
There are some drawbacks to the IDE release, mainly for Mac users. The IDE runs under OS X and can produce even GUI applications using the EiffelVision libraries—but as X11 applications. These don’t integrate very well into OS X. However, given Eiffels vaunted interoperability with other languages, it should be possible to build program logic in Eiffel, gaining robustness and clarity from the design powers of the language, and to integrate those objects into OS X applications using Objective-C or Java (using JNI).
To be fair to C#, it doesn’t seem to be as content to linger in the past as Java. The Linq Project is a “set of extensions to the .NET Framework that encompass language-integrated query, set, and transform operations.” The C# 3.0 Language Specification (in Microsoft Word format)[8] describes the feature and its deep integration into the next version of C#. This feature is anchored by type inference, which allows develoepers to leave off explicit types in cases where the type is clear from the context. The lambda expressions available in C# 3.0 come from functional languages and allow chunks of executable code to be passed around a C# program (analogous to Eiffel agents, though not as flexible). The LINQ Project overview offers more details in a web page (instead of a Word document).
Which Java and C# don’t have anyway, but which can be emulated using assertions and “Do” routines. For example, for the non-virtual public function, f (p1: A), there is a virtual function do_f (p1: A), which is called from f, after it asserts pre-conditions and before it asserts its post-conditions, as in the example below (show in Java notation):
public void function f (A p1) {
assert( f_precondition );
do_f (p1);
assert( f_postcondition );
}
protected void function do_f (A p1) {
// to be implemented in descendents
}
This approach, though workable, does little to enhance clarity of design and does not solve the problem of inheriting from multiple such implementations to maximize reuse.
↩A[G]
, with descendent B[G]
(where G is generic), and X
with descendent Y
, we expect B[Y]
to conform to A[X]
. In Eiffel, it does; in C# and Java, it does not. Further, if A
declares function f (p1: G): G
, we expect the function in A[X]
to be expressed as f (p1: X): X
and the function is B[Y]
to be f (p1: Y): Y
. Since both Java and C# lack parameter covariance, it is a compiler error to use a generic type for a function argument. Since they do support function result covariance, the version in A[X]
is f (p1: X): X
and that in B[Y]
is f (p1: X): Y
. Inside the implementation of f
in B[Y]
, one must once again resort to a cast in order to get the type one would already be assured of in Eiffel.↩A
, with attribute a1: A
. The function to set this attribute could be declared as set_a1 (a2: like a1)
. If B
inherits this attribute and redefines it (using function result covariance) to a1: B
, the argument to function set_a1
is automatically redefined as well. If this is always desired, the original parameter in A
could be declared as a1: like Current
, where Current
is the equivalent of this
in C# and Java.↩