Eiffel for .NET: An Introduction

Eiffel for .NET: An Introduction

his article describes the goals and scope of the Eiffel language and explains how Eiffel for .NET can interoperate with other .NET languages. The article also demonstrates using Eiffel for .NET to build graphical user interfaces, using Windows Forms, to access databases and develop Web services.

The Fundamentals of Eiffel for .NET
The .NET platform contains some innovative development concepts including language interoperability and extensive support for development of Web services. The .NET platform also provides a rich collection of software facilities (security, component-based development, versioning, memory management, etc.), which make it a powerful development tool in the field of computing. With all of this innovation, Eiffel Software, Inc. (ESI) decided to give Eiffel programmers the chance to benefit from all of these innovations while also giving .NET users a chance to benefit from the power of Eiffel. This effort resulted in Eiffel for .NET, bringing Design by Contract, multiple inheritance and genericity to the .NET world.

Eiffel was ported to the .NET environment from the very beginning of .NET. The first version was called Eiffel#. This version is now obsolete being replaced by Eiffel for .NET.

Fast Facts
Eiffel for .NET provides a best-of-breed solution for software development on the .NET Framework. This article explains the fundamentals of Eiffel for .NET and gives concrete examples for programmers.

Design by Contract
Like Eiffel, Eiffel for .NET directly enforces Design by Contract through constructs such as class invariants, routine preconditions and postconditions, check instructions and loop invariants. The idea of programming with contracts (inspired by commercial relationships and business contracts) is to formally express the rights and obligations binding a client and a supplier, which addresses the following issues:

  • Correctness: Contracts help build software right in the first place.
  • Documentation: Contracts make it possible to automatically extract documentation from the code itself.
  • Debugging and testing: Run time monitoring of contracts facilitates detection of errors in the software text.
  • Inheritance control: The principles of Design by Contract provide a coherent approach to inheritance, limiting the extent to which new routine definitions can affect the original semantics (pre-conditions can only be weakened while post-conditions can only be strengthened).
  • Management: Contracts help onlookers to better understand the global meaning of a program without looking at the core implementation.

A recent report by the Software Engineering Institute highlights the usefulness of contracts, confirming that the use of contracts in building components is a key factor in improving software composability and reusability.

Eiffel for .NET is the sole language on the .NET Framework to support contracts natively. Some other languages do have contracts, but not as a language construct: they provide add-ons to support it. The weaknesses of such approaches mostly deal with dynamic contract checking and contract inheritance (especially multiple inheritance).

In the specific context of .NET, ESI has developed a Contract Wizard. The Contract Wizard gives developers the ability to add contracts to the classes and routines of an existing .NET assembly. The Contract Wizard builds a “proxy” assembly, which has the contracts, but calls the original assembly code. This solution takes advantage of the flexibility of the .NET component model, in particular the notion of metadata (interface information that every assembly includes).

This approach provides a way to “contract” a component a posteriori, which should help understand the library better, improve its documentation and make it safer to use. It also benefits from its internal use of Eiffelas: an intermediate language to add contracts?providing inheritance of assertions (contrary to most “contract tools” for non-Eiffel languages, such as iContract and Jcontract in Java).

However, the right time to put in the contracts, in good library development, is during design. A posteriori addition of contracts can never be as efficient as a native implementation with contracts. For example, one cannot avoid the speed penalty of looking up the assembly metadata. It also takes time for users to enter assertions after the fact, which can become prohibitive when dealing with large-scale software development. Finally, a posteriori contraction is helpless regarding the design of the existing libraries: the contracted component is just an “Eiffel mapping” of its .NET counterpart. For example, components developed with a language that does not support contracts often use a very “defensive” style of programming (checking the routine requirements with If statements), which can yield rather inefficient software, especially when the software is big and such checks numerous. Eiffel for .NET users simply rely on assertions, leading to a lighter and more efficient programming style.

Seamlessness of Software Development
The “natural” environment to develop your Eiffel applications is EiffelStudio, although you will see later that this is not the only choice.

Figure 1: EiffelStudio: The Eiffel development environment.

One of the strong points of Eiffel is that it covers the entire software lifecycle. EiffelStudio (see Figure 1) enables you to put this method into practice: you can use it from analysis and design to implementation and maintenance with complete seamlessness between each step of development. In particular, EiffelStudio provides an integrated Diagram Tool to help you construct and read complex inheritance structures. The Diagram Tool would not be anything special by itself (drawing inheritance relationships could be done with UML as well); its real power comes from its interaction with the other facilities of the EiffelStudio. These capabilities make EiffelStudio an innovative and convenient tool for large-scale software construction. The Diagram Tool is fully “clickable,” meaning that the user can navigate between classes?including class texts?easily and intuitively, as if he or she was following hyperlinks on the Web. It also provides complete reversibility between the text and graphical views of your system, updating the software text?after compilation?whenever you change the graphics, and conversely.

The latest release of EiffelStudio was reviewed in Software Development Magazine in May 2002 as an “excellent environment for developing object-oriented applications with a well-tested, elegant OO programming language.”Mapping non-CLS Compliant Mechanisms on .NET

Eiffel for .NET (in the EiffelStudio 5.1 IDE) is the only language in the .NET world to provide multiple inheritance and genericity.

Eiffel for .NET (in the EiffelStudio 5.1 IDE) is also the only language in the .NET world to provide multiple inheritance and genericity (see the “Eiffel Terminology” sidebar). Providing such advanced language mechanisms in an environment that does not support them (multiple inheritance and genericity do not conform to the Common Language Specification, CLS, of .NET) was quite a challenge. As a matter of fact, ESI wanted its implementation of Eiffel for .NET to be fully interoperable with the other .NET languages: any client should be able to reuse an Eiffel for .NET component in any way (client or inheritance relationship), and conversely Eiffel for .NET users should be able to reuse any .NET assembly (the unit of reuse in .NET).

Multiple inheritance was a major implementation issue. The adopted solution takes advantage of the .NET support for multiple inheritance of interfaces (fully deferred classes): the Eiffel for .NET compiler shadows each class with an interface (see Figure 2). The “shadow interface” has the original class name (for example, A), since it is viewed from the outside world, and includes only interface elements (all the class features are declared as deferred). The implementation is moved to the automatically generated class called “Impl.ORIGINAL_CLASS_NAME” (for example, Impl.A). Here, “Impl” stands for “Implementation.”

This mapping preserves the original inheritance hierarchy. As shown in Figure 2, interface C inherits from the interfaces A and B as the initial class C inherited from the classes A and B. Hence, there is no need for .NET programmers to know about the automatically generated classes (at least, client classes do not have to; descendants will have to inherit from the Impl class); they just remain a compiler issue.

However, this technique raises a problem, which is class instantiation. As a matter of fact, the “non-Impl” entities are now interfaces, not classes, thus not instantiable. Hence, the Eiffel for .NET compiler generates a second set of classes, the “Create classes,” which provide the necessary mechanisms to emulate class constructors (see Figure 3).

Figure 3: Complete mapping of multiple inheritance used in Eiffel for .NET.

You might be concerned of the cost of such a mapping, resulting in three times as many classes?three times as many objects at run time?as the original architecture. The ESI experience proved this mechanism to be reliable and efficient: the penalty introduced with the extra classes appears trifling comparing to the gain of having multiple inheritance.

This mechanism fully relies on the .NET concept of namespace since Impl and Create are simply .NET namespaces. I will provide code examples later.

Genericity has been supported in Eiffel for .NET from the very beginning?since Eiffel#?contrary to multiple inheritance, which was only recently introduced with the second implementation of Eiffel on the .NET Framework.

The technique retained for genericity is different from the one presented above for multiple inheritance. As a matter of fact, applying rules such as those just sketched would yield an explosion of classes?and an explosion of objects at run time?since the compiler would generate as many classes as class derivations; for example, you would have LIST [INTEGER], LIST [STRING], LIST [BOOLEAN], and so on, for just one generic class LIST [G]?where G is the formal generic parameter. This is clearly not scalable and is, therefore, unacceptable. Instead, the Eiffel for .NET compiler uses LIST [ANY], which in the .NET world corresponds to list of Object (Object is the top level class from which any .NET class inherits).

Covariance is also available in Eiffel for .NET, although the Common Language Runtime (CLR) does not support it (because of type safety issues that full covariance implies, also known as “polymorphic catcalls” in Eiffel). Eiffel for .NET implements a safe variant of covariance, with type checking, to avoid catcalls: the CLR raises an exception of type InvalidTypeException whenever a catcall may happen. Another advantage of this approach is that CLS compliant consumer tools can understand it, and benefit from the Eiffel for .NET covariance.Full Interoperability with Other .NET Languages
Now that you understand the scope of Eiffel for .NET and how it interoperates with the .NET Framework, let’s continue with a Hello World example and how to reuse an Eiffel for .NET component from two other languages: C# and Visual Basic .NET.

A Hello World Example with Eiffel for .NET
Listing 1 gives a possible implementation of a Hello World sample using Eiffel for .NET.

Compiling the sample produces a .NET assembly that is language independent. This assembly can be reused from any .NET language without knowing it was programmed in Eiffel for .NET.

Reusing an Eiffel for .NET Component from C# and VB.NET
Reusing an Eiffel for .NET component from C# (or VB.NET) is almost transparent to the software developer.

As a client, the only difference is in the instantiation of a type originally written in Eiffel for .NET: the programmer has to use the generated Create class mentioned before.

The sample below reuses the Eiffel for .NET component generated from the Hello World sample presented earlier (see Listing 1) as a client:

   public class HelloWorld1   {      public static void Main()      {         HelloWorld sample;         sample = Create.HelloWorld.Make();      }   }

In Listing 1, the class is called HELLO_WORLD whereas the class name used in the sample above is Create.HelloWorld. How can it be? You can set the option “dotnet_naming_convention” in the project settings file (the ACE file) to force the Eiffel for .NET compiler to generate .NET-friendly names. This option is disabled by default. However, if that feature is enabled, class and feature names are changed using the following conventions: my_feature becomes MyFeature and MY_CLASS becomes MyClass. Therefore, in our example, HELLO_WORLD has been changed to HelloWorld.

Once class HelloWorld has been instantiated, the C# programmer can use the object (sample in the above code) like any other C# object, transparently from its original Eiffel for .NET implementation.

Here is the VB.NET counterpart of the example:

   Public Class HelloWorld1         Public Sub Main()         Dim sample as HelloWorld         sample = Create.HelloWorld.Make()      End Sub      End Class

As an heir, the C# class has to know about the generated Impl class (since the original class name refers to an interface). With this exception, inheriting from an Eiffel for .NET class is the same as inheriting from a C# class: all exported features are available to the descendant.

The following code reuses the Hello World sample shown in Listing 1 as a descendant: it inherits from the generated class Impl.HelloWorld and uses the method HelloWorldMessage originally defined in the Eiffel for .NET class as the String constant Hello_world_message.

   using System;   public class HelloWorld2:Impl.HelloWorld   {      public static void Main()      {         HelloWorld2 h2;         h2 = new HelloWorld2();         Console.WriteLine (h2.HelloWorldMessage());      }   }

Here is the same example written in VB.NET:

   Imports System   Public Class HelloWorld2      Inherits Impl.HelloWorld         Public Shared Sub Main()         Dim h2 as HelloWorld2            h2 = new HelloWorld2()         Console.WriteLine (h2.HelloWorldMessage())      End Sub      End Class

Integration in Visual Studio .NET
Eiffel for .NET is a released product and is available as part of the ESI’s EiffelStudio 5.1. The forthcoming release of ESI’s EiffelStudio 5.2, will provide major improvements in the areas of speed, efficiency and reliability.

In September 2002, ESI will release Eiffel ENViSioN! 1.0, a stand-alone plug-in for Visual Studio .NET. Eiffel ENViSioN! represents a major accomplishment in porting Eiffel to the .NET Framework, allowing developers to use the Eiffel method and language seamlessly within Microsoft’s Visual Studio .NET. Eiffel programmers will appreciate the cross-language browsing and debugging facilities of Visual Studio .NET while VS.NET users will take advantage of Eiffel mechanisms such as the smart editor (with automatic completion of class and feature names) and project cluster browsing facilities of EiffelStudio.

Providing full interoperability with the other .NET programming languages gives Eiffel developers the opportunity of using two complementary development environments; EiffelStudio and Visual Studio .NET.

With Eiffel ENViSioN!, Eiffel for .NET users have the possibility to always select the programming environment that is best suited for their project:

  • EiffelStudio for full-Eiffel development (see Figure 1).
  • Visual Studio .NET for multi-language development (see Figure 4).

Figure 4 shows a multi-language project developed under Visual Studio .NET; it involves three .NET programming languages: C#, Visual Basic .NET and Eiffel.

Figure 4: A multi-language project with Visual Studio .NET.

As mentioned before, one key feature of Visual Studio .NET is its support for cross-language debugging. Figure 5 illustrates a debugging session under VS.NET for an Eiffel project. You can see:

  • The place in a routine text where the execution is currently stopped (top-left pane).
  • The browsing facilities, using the same conventions as within EiffelStudio (top-right pane).
  • The local variables, with their declaring types and values (bottom-left pane). This panel also lets you define “watch lists” and evaluate expressions on the fly.
  • The compiler output (bottom-right pane).
Figure 5: A debugging session under Visual Studio .NET.

These examples reveal the complementary nature of the two development environments that Eiffel for .NET users have at their disposal. Thus, having the choice between them is a major advantage.Windows Forms and Eiffel for .NET
Eiffel for .NET takes full advantage of the .NET platform. In particular, you can reuse the whole set of libraries provided via the .NET Framework. The next step is to build a graphical application using the Windows Forms library using Eiffel for .NET.

Building Graphical Applications with .NET Windows Forms
As a basis of comparison, Listing 2 shows a possible implementation of a simple Windows Form application written in C#.

This application is not fancy (see Figure 6) and illustrates only how to use the Windows Forms library.

Figure 6: The “Hello World!” Windows form.

EiffelStudio provides an Eiffel for .NET Base Class library, which follows the design principles found in the standard EiffelBase. This library makes extensive use of contracts and genericity to provide a clean and powerful set of reusable data structures. The actual implementation of “EiffelBase.NET” calls the Base Class library of the .NET Framework.

As for other .NET libraries, EiffelStudio provides a set of wrapper classes that enable you to reuse the corresponding types in your Eiffel for .NET applications. This is the case of the Windows Forms library.

Listing 3 shows how to develop the Windows Forms application just presented (see Listing 2) in Eiffel for .NET.

This code sample shows that class and feature names are the main differences between the C# and Eiffel for .NET versions. For example, the .NET class System.Windows.Forms.Form is called WINFORMS_FORM; System.Windows.Forms.Button is called WINFORMS_BUTTON, etc. Constructors are expressed by creation routines of the form “make_winforms_*”, and property setters are replaced by “set” procedures (set_text, set_location, etc.).

Why such differences? The main reason is overloading: although part of the Common Language Specification of .NET, Eiffel does not support it. Hence, there will be name clashes for every overloaded feature that the Eiffel for .NET compiler needs to solve. The second reason is Eiffel naming convention: use of lower case and underscores rather than camel case. The Eiffel approach (and syntax) pursues the basic goal of software engineering: producing reliable software. It applies a fundamental rule of software construction: the principle of non-deception, stating that “differences in semantics should be reflected by differences in the text of the software.” This rule is essential to improve the readability of the software text and minimize the risk of errors.

Figure 7: The architecture of EiffelVision2, the portable Eiffel graphical library.

Apart from such name mismatches, the use of Windows Forms is similar in Eiffel for .NET and C# (or any other .NET programming language).

Assembly dependencies?in this case, System.Windows.Forms.dll and System.Drawing.dll?are specified in your project settings that you can edit within EiffelStudio or Visual Studio .NET. (In C# or VB.NET, you would add the -r option to compile your project.)

Building Graphical Applications with the Eiffel Graphical Library
While having a set of class wrappers is nice, this is not always satisfactory. In the same way there is an EiffelBase for .NET with carefully expressed contracts, Eiffel for .NET also provides its own graphical library (EiffelVision2) on .NET. Listing 4 gives you an idea of what an EiffelVision2 application looks like.

The major advantage of using EiffelVision2 is platform portability. As a matter of fact, it is a fully portable library that offers an object-oriented framework for graphical user interface (GUI) development. It runs on Windows and all major versions of Unix (including Linux). It relies on a two-tiered architecture illustrated in Figure 7. WEL (Windows Eiffel Library) wraps the Windows API while GEL (GTK Eiffel Library) wraps the GTK APIs.

Figure 8: EiffelVision application with a Windows Forms Datagrid displaying the content of a database through ADO.NET.

Combining Graphical User Interfaces and Database Access with Eiffel for .NET

Particularly interesting is the ability to combine the EiffelVision2 mechanisms with the .NET facilities, such as Windows Forms. For example, you may want to display, in a possibly complex EiffelVision application, the contents of a database in a Windows Form Datagrid through ADO.NET. Figure 8 shows such a Datagrid, displayed as part of an EiffelVision window.

Web Services with Eiffel for .NET
The .NET Framework is built with the idea of Web services in mind: it provides the libraries needed to develop them (refer to the System.WebServices and System.Web.UI namespaces in the documentation). The next section describes building Web services in Eiffel for .NET.A Registration Page Demo

Figure 9: An Eiffel for .NET Web service (conference registration page).

This demo represents a registration service for a conference. It provides two main pages: a registration page for attendees (see Figure 9) and a status page showing the current state of registrations (for the organizers of the conference).

Listing 5 is an extract of the underlying ASP.NET code.

This ASP.NET implementation contains HTML code (for the Web page layout) and C# code.

The following line tells you that the code written in the