Eiffel Classes

The unit of software reuse in Eiffel is the class.

The unit of modularity in Eiffel is the class.

The unit of type modeling in Eiffel is the class.

All Eiffel code must exist within the context of a class.

In Eiffel, application systems, or simply systems, are created by assembling a set of related classes. The classes in a system will be related only by one or both of the two allowable relationships in object-oriented design.

Having read the above, you should be convinced that the concept of class is important and far-reaching. The fact that we have precise rules about classes simplifies life a lot. The only kind of module in Eiffel is a class. Each class exists in one source file (which contains only that class), and contains the code necessary to provide a static definition of a data type. Every runtime entity, i.e. every object, must be an instance of a class. Because we can depend upon these things in Eiffel, we have consistency and predictabililty in the inherently complex world of software development.

Let's take a look at how classes are structured.

The code that makes up an Eiffel class is divided into the following parts:

Structure of a Class

All of the above, except Class header, are optional. So the simplest Eiffel class you could build would look like this: class SIMPLE end

Okay, so class SIMPLE is only interesting in its simplicity. Let's look at an example that is more illustrative: note description: Objects that model lists revision: $Revision: 1.4 $ class OLD_FASHIONED_LIST [G] obsolete "This class is obsolete, use LINKED_LIST [G] instead" inherit DYNAMIC_LIST [G] create make feature -- Initialization make -- Create an empty list. do before := True ensure is_before: before end feature -- Access item: G -- Current item do Result := active.item end first: like item -- Item at first position do Result := first_element.item end ... other features omitted ... invariant before_constraint: before implies (active = first_element) after_constraint: after implies (active = last_element) Here is a class that, although completely contrived, utilizes all of the required and optional parts of the class. Let's look at each part individually.

Note

note description: Objects that model lists revision: $Revision: 1.4 $

The note part of a class is there to allow you as a producer to record information of your choice which will help you or other reuse consumers at some later time to locate understand the class. This important in Eiffel because we try to treat every class as if someday it will become reusable.

Information in note does not change the semantics of the class.

The note part in the class above is typical. It is introduced with the language keyword note, and contains two note clauses, each of which is comprised of an index and a single index value. You can code note clauses with indexes that you devise yourself, so there is nothing inherently special about "description" and "revision" as used above. But, these indexes could be special to tools which analyze libraries of classes use them. Although these clauses have only one index value each, it is permissible to put more, separated by commas.

Class Header

class OLD_FASHIONED_LIST [G]

The class header is introduced by the keyword "class", which in turn can be preceded by one of three keywords which mark the class as deferred, expanded, or frozen. In our example, the class has none of these markings, so it is an effective class whose instances are access by reference.

The keyword class is followed by the class name, in this case "OLD_FASHIONED_LIST".

Of the three keywords for header marks, the one which you will encounter most often is deferred. A class is deferred if it contains one or more features that are deferred, that is, features which have been specified in the class but for which no implementation has been provided. Proper descendants of a deferred class will provide implementations for its deferred features.

Formal Generics

class OLD_FASHIONED_LIST [G]

In this example the class name is followed by the specification of one formal generic parameter "G". The presence of one or more formal generic parameters will designate a class as a generic class. The formal generic parameter is a place holder for a class name which will be provided by reuse consumers. For example if we wrote a class which was a client to OLD_FASHIONED_LIST we would substitute the class name for the type of objects that we would want to build an OLD_FASHIONED_LIST of. We might make this declaration: my_list_of_cats: OLD_FASHION_LIST [CAT]

The entity my_list_of_cats could then be attached at runtime to an OLD_FASHIONED_LIST of objects of type CAT. So the class CAT becomes an actual generic parameter and substitutes for G in the declaration.

Of course formal generic parameters cannot be the same name as a class name in the same universe. If multiple formal generic parameters are used, they are separated by commas.

You will learn more about generic classes in the section titled Genericity .

Obsolete

obsolete "This class is obsolete, use LINKED_LIST [G] instead"

OLD_FASHION_LISTs are obsolete ... and the class is marked as such by include the line above. The manifest string contains an explanation, instructions, and/or recommended alternatives. Compilers and other language tools can deliver this message to potential reuse consumers. As with note, obsolete has no effect on the semantics of the class.

Obsolete is rarely used because of the nature of certain elements of the Eiffel methodology. For example, if implementations are well-hidden behind implementation-independent specifications, then those implementations may be changed to adapt the class to changing execution environments in such a way that clients are unaffected.

Inheritance

inherit DYNAMIC_LIST [G]

One of the two possible relationships between classes, inheritance is also a powerful software reuse mechanism. In this example class OLD_FASHIONED_LIST declares itself to be a proper descendant of class DYNAMIC_LIST.

There will be more in the section called . For now though, be aware of two important implications of this declaration:

  • Every feature of DYNAMIC_LIST is available to OLD_FASHIONED_LIST and potentially available to its clients.
  • Whenever an instance of DYNAMIC_LIST is called for, then an instance of OLD_FASHIONED_LIST will suffice.

Creators

create make

The creators part of a class declares a procedure as being a creation procedure. In this case the procedure in question is the one named make. By convention, creation procedure names begin with the word " make".

Let's take a quick look at object creation. Consider this declaration: my_list_of_cats: OLD_FASHION_LIST [CAT]

Here the entity my_list_of_cats can be attached to an object of type OLD_FASHION_LIST [CAT] at runtime. The process of converting my_list_of_cats from holding a void reference to holding a reference to a object modeling a list of cats, starts when a creation instruction is executed. The creation instruction creates the instance and may apply a creation procedure to initialize the instance. A creation instruction for the declaration above would look like this: create my_list_of_cats.make

The create keyword is used to introduce a creation instruction. This instruction causes the following four things to happen:

  • A shell of a new instance of OLD_FASHION_LIST [CAT] is created in memory with a memory field for every attribute
  • Each field is initialized with standard default values
    • False for type BOOLEAN
    • Null character for type CHARACTER
    • The appropriate form of zero for number types
    • Void for reference types
  • Attach the new instance to the entity my_list_of_cats
  • Apply the creation procedure make

Once these steps complete successfully, my_list_of_cats will be attached to a valid instance (i.e., an instance in which the class invariant is true) of OLD_FASHIONED_LIST [CAT].

Features

feature -- Initialization make -- Create an empty list. do before := True ensure is_before: before end feature -- Access item: G -- Current item do Result := active.item end first: like item -- Item at first position do Result := first_element.item end

The features part of a class is the area in which we feel that most of the "programming" is done. It is here that we define those things that instances of a class have and can do. We will learn more about features in the next section Adding Class Features .

Until then let's just take a quick look at how features fit into a class. Notice that in our example the features part is introduced by the keyword "feature". In fact there are two occurrences of feature in this example, each followed by a comment.

You may declare multiple feature statements. This helps you group features in a manner that makes sense. Here we see the first group contains those features which are listed as creation procedures in the creators part of the class. The second group of features labeled "Access" contains a set of queries available to clients of the class.

Although the words "Initialization" and "Access" are actually in comments after the feature keyword, some language processing tools apply some significance to these, for example, ordering the groups in "pretty-printed" views of a class. Also, some tools allow you to build templates for creating new classes which have feature clauses already in place for predetermined groups.

Tip: There is not a technical requirement governing the grouping or ordering of features in a class. It is the option of the producer of a class to group and order the features in a fashion that holds some meaning. Many years of Eiffel development experience are reflected in the classes in the EiffelBase Library. This is a good place to look for examples of well constructed classes.

Invariant

invariant before_constraint: before implies (active = first_element) after_constraint: after implies (active = last_element)

Here's the last word in a class definition ... both literally and figuratively. The invariant part, introduced not surprisingly by the keyword "invariant", is that portion of the class in which we can state what it means for an object to be a valid instance of this class.

We will learn more about class invariants in the section titled Design by Contract and Assertions .

cached: 03/19/2024 3:43:51.000 AM