Previous Table of Contents Next


Dynamic binding is particularly interesting for polymorphic data structures. If we iterate over the list of accounts of various kinds, accounts: LIST [ACCOUNT], illustrated in Figure 9.10, and at each step let acc represent the current list element, we can repeatedly apply acc.deposit (...) to have the appropriate variant of the deposit operation triggered for each element.

The benefit of such techniques appears clearly if we compare them with the traditional way to address such needs: using multibranch discriminating instructions of the form ifAccount is a savings accountthen ...elseifIt is a money market accountthen ... and so on, or the corresponding case ... of ...or inspect instructions. Apart from their heaviness and complexity, such solutions cause many components of a software system to rely on the knowledge of the exact set of variants available for a certain notion, such as bank account. Then, any addition, change, or removal of variants can cause a ripple of changes throughout the architecture. This is one of the major obstacles to extendibility and reusability in traditional approaches. In contrast, using the combination of inheritance, redefinition, polymorphism, and dynamic binding makes it possible to have a point of single choice—a unique location in the system that knows the exhaustive list of variants. Every client then manipulates entities of the most general type, ACCOUNT, through dynamically bound calls of the form acc.some_account_feature (...).

These observations make dynamic binding appear for what it is: not an implementation mechanism, but an architectural technique that plays a key role (along with information hiding, which it extends, and design by contract, to which it is linked through the assertion redefinition rules seen later) in providing the modular system architectures of Eiffel, the basis for the method’s approach to reusability and extendibility. These properties apply as early as analysis and modeling, and continue to be useful throughout the subsequent steps.

9.9.5. Deferred Features and Classes

In the preceding examples of dynamic binding, all classes were assumed to be fully implemented, and dynamically bound features had a version in every relevant class, including the most general ones such as ACCOUNT.

It is also useful to define classes that leave the implementation of some of their features entirely to proper descendants. Such an abstract class is known as deferred; so are its unimplemented features. The reverse of deferred is effective, meaning fully implemented.

LIST is a typical example of deferred class. As it describes the general notion of list, it should not favor any particular implementation; that is, the task of its effective descendants, such as LINKED_LIST (linked implementation), TWO_WAY_LIST (linked both ways), and ARRAYED_LIST (implementation by an array), all effective, and all indeed to be found in ISE’s EiffelBase libraries.

At the level of the deferred class LIST, some features such as extend (add an item at the end of the list) have no implementation and hence are declared as deferred. Here is the corresponding form, illustrating the syntax for both deferred classes and their deferred features:

   indexing
       description: “Sequential finite lists,
           without a commitment to a representation”
   deferred class
       LIST [G]
   feature  -- Access
       count: INTEGER is
                -- Number of items in list
           do
               ... See below; this feature can be effective ...
           end
   feature  -- Element change
       extend (x: G) is
                -- Add x at end of list.
           require
               space_available: not full
           deferred
           ensure
               one_more: count = old count + 1
           end
   ... Other feature declarations and invariant ...
   end  -- class LIST

A deferred feature (considered to be a routine, although it can yield an attribute in a proper descendant) has the single keyword deferred in lieu of the do Instructions clause of an effective routine. A deferred class—defined as a class that has at least one deferred feature—must be introduced by deferred class instead of just class.

As the example of extend shows, a deferred feature, although it has no implementation, can be equipped with assertions. They are binding on implementations in descendants, in a way to be explained later.

Deferred classes do not have to be fully deferred. They can contain some effective features along with their deferred ones. Here, for example, we may express count as a function:

   count: INTEGER is
            -- Number of items in list
       do
           from start until after loop
               Result := Result + 1; forth
           end
   end


Previous Table of Contents Next