Previous | Table of Contents | Next |
A feature, as noted, is an operation available on instances of a class. A feature can be either an attribute or a routine. This classification, which can be followed by starting from the right on Figure 9.5, is based on implementation considerations.
FIGURE 9.5 Feature categories (two complementary classifications).
Routines are further classified into functions, which return results, and procedures, which do not. Routine withdraw is a procedure; an example of a function may be highest_deposit, which returns the highest deposit made so far to the account.
From the viewpoint of classes relying on a certain class (its clients), the more relevant classification is the one coming from the left on Figure 9.5:
From the outside, there is no difference between a query implemented as an attribute and one implemented as a function: To obtain the balance of an account a, you always write a.balance.
In the implementation suggested previously, a is an attribute so that the notation denotes an access to the corresponding object field. It is also possible to implement a as a function, whose algorithm explores the lists of deposits and withdrawals and computes their accumulated value. To the clients of the class, and in the official class documentation as produced by the environment tools, the difference is not visible.
This principle of uniform access supports Eiffels goals of extendibility, reusability, and maintainability: You can change the implementation without affecting clients, and you can reuse a class without having to know the details of its features implementations.
The following simple class text illustrates the preceding concepts:
indexing description: Simple bank accounts class ACCOUNT feature -- Access balance: INTEGER -- Current balance deposit_count: INTEGER is -- Number of deposits made since opening do if all_deposits /= Void then Result := all_deposits.count end end feature -- Element change deposit (sum: INTEGER) is -- Add sum to account. do if all_deposits= Void then !! all_deposits end all_deposits.extend (sum) balance := balance + sum end feature {NONE} -- Implementation all_deposits: DEPOSIT_LIST -- List of deposits since accounts opening. invariant consistent_balance: (all_deposits /= Void) implies (balance = all_deposits.total) zero_if_no_deposits: (all_deposits = Void) implies (balance = 0) end -- class ACCOUNT
(The {NONE} qualifier and the invariant clause, used here to make the example closer to a real class, are explained shortly. DEPOSIT_LIST refers to another class, which can be written separately using library classes.)
The category to which each feature belongs is easy to deduce from its syntactic appearance. Here only deposit and deposit_count, which include a do... clause, are routines; balance and all_deposits, which are simply declared with a type, are attributes. Note that even for attributes it is recommended to have a header comment.
Routine deposit_count is declared as returning a result (of type INTEGER), so it is a function. Routine deposit has no such result and hence is a procedure.
Previous | Table of Contents | Next |