Previous | Table of Contents | Next |
The preceding elements make it possible to understand the overall scheme of an Eiffel systems execution.
At any time during the execution of a system, one object is the current object of the execution, and one of the routines of the system, the current routine, is executed with the current object as its target. (You will see later in this chapter how the current object and current routine are determined.) The text of a class, in particular its routines, make constant implicit references to the current object. For example, in the instruction
balance := balance + sum
appearing in the body of procedure deposit of class ACCOUNT, the name of the attribute balance, in both occurrences, denotes the balance field of the current object, assumed to be an instance of ACCOUNT. In the same way, the procedure body that we have used for the creation procedure make in the ACCOUNT1 variant
make (sum: INTEGER) is -- Initialize account with sum. do deposit (sum) end
contains a call to the procedure deposit. Contrary to earlier calls written in dot notation as target.feature (...), the call to deposit has no explicit target; this means its target is the current object, an instance of ACCOUNT1. Such a call is said to be unqualified; those using dot notations are qualified calls.
Although most uses of the current object are implicit, a class may need to name it explicitly. The predefined expression Current is available for that purpose. A typical use, in a routine merge (other: ACCOUNT) of class ACCOUNT, would be a test of the form
if other = Current then report_error (Error: trying to merge an account with itself !) else ... Normal processing (merging two different accounts) ... end
With these notions, it is not hard to define precisely the overall scenario of a system execution by defining what object and routine will be the current object and the current routine at each instant:
The description of assignments stated that in x := y, the target x must be an entity. More precisely, it must be a writable entity; this excludes formal routine arguments. As noted, a routine r (arg: SOME_TYPE) cannot assign to arg (reattaching it to a different object), although it can change the attached objects through calls of the form arg.procedure (...).
The restriction to an entity precludes in particular assignments of the form obj.some_attribute := some_value because the left-hand side, obj.some_attribute, is an expression (a feature call), not an entity, and you can no more assign to obj.some_attribute than to, say, a + banother expression that is also, formally, a feature call.
To obtain the intended effect of the invalid assignment, you can use a procedure call of the form obj.set_attribute (some_value), where the base class of objs type has defined the procedure
set_attribute (v: VALUE_TYPE) is -- Set value of attribute to v. do attribute := v end
This rule is essential to enforcing the method. Permitting direct assignments to an objects fields would violate all the tenets of information hiding by circumventing the interface carefully crafted by the author of the supplier class. It is the responsibility of each class author to define the exact privileges that the class gives to each of its clients, in particular field modification rights. A field can be totally hidden (when the corresponding attribute is exported to NONE); it can be exported in read-only mode (when the attribute is exported, but no procedure modifies it); it can be exported in free-write mode (as with set_attribute if the class exports this procedure); it can also be exported in restricted-write mode, as with procedure deposit of class ACCOUNT, which allows addition of a certain amount to the balance field, but not direct setting of the balance. In such a case, the exported procedures may, thanks to the assertion mechanism reviewed later (section 9.8), place some further restrictions on the permitted modificationsfor example, by requiring the withdrawn amount to be positive.
Previous | Table of Contents | Next |