Previous Table of Contents Next


In the case of procedures, this provides a convenient initialization mechanism. A delicate problem in the absence of a once mechanism is how to provide the users of a library with a set of routines that they can call in any order, but that all need, to function properly, the guarantee that some context had been properly set up. Asking the library clients to precede the first call with a call to an initialization procedure setup is not only user-unfriendly but silly: In a well-engineered system, we want to check setup in every of the routines and report an error if necessary. But then if we were able to detect improper setup, we might as well shut up and set up (by calling setup) ourselves instead. This is not easy, however, because the object on which we call setup must itself be properly initialized, so we are only pushing the problem further. Making setup a once procedure solves it: We can simply include a call

   setup

at the beginning of each affected routine; the first one performs the needed initializations; subsequent calls have, as desired, no effect.

once functions give us shared objects. A common scheme is

   console: WINDOW is
            -- Shared console window
       once
           !! Result.make (...)
       end

The first call creates the appropriate window and returns a reference to it. Subsequent calls, from anywhere in the system, return that same reference. The simplest way to make this function available to a set of classes is to include it in a class SHARED_STRUCTURES, which the classes needing a set of related shared objects simply inherit.

For the classes using it, console, although a function, looks very much as if it were an attribute—only one referring to a shared object.

The “Hello, World” system at the beginning of this chapter (section 9.4) uses an output instruction of the form io.put_string (“Some string”). This is another example of the general scheme illustrated by console. Feature io, declared in GENERAL and hence usable by all classes, is a once function that returns an object of type STANDARD_FILES (another kernel library class) providing access to basic input and output mechanisms. Procedure put_string is one of them. Because basic input and output must all work on the same files, io should clearly be a once function, shared by all classes that need these mechanisms.

9.10.2. Constant Attributes

The attributes studied earlier were variable: Each represents a field present in each instance of the class and changeable by its routines.

It is also possible to declare constant attributes, as in

   Solar_system_planet_count: INTEGER is 9

These have the same value for every instance and hence do not need to occupy any space in objects at execution time. (In other approaches, similar needs would be addressed by constants, as in Pascal or Ada, or macros, as in C.)

What comes after the is is a manifest constant: a self-denoting value of the appropriate type. Manifest constants are available for integers, reals (also used for doubles), booleans (True and False), and characters (in single quotes, as ‘A’, with special characters expressed using a percent sign as in ‘%N’ for newline, ‘%B’ for backspace, and ‘%U’ for null).

For integer constants, it is also possible to avoid specifying the values. A declaration of the form

   a, b, c, ... n: INTEGER is unique

introduces a, b, c, ... n as constant integer attributes, whose values are assigned by the Eiffel compiler rather than explicitly by the developer. The values are different for all unique attributes in a system; they are all positive, and, in a single declaration such as the preceding, guaranteed to be consecutive (so that an invariant property of the form code >= a and code <= n can be used to express that code should be one of the values). This mechanism replaces the enumerated types found in Pascal and subsequent languages without suffering from the same problems. (Enumerated types have an ill-defined place in the type system, and it is not clear what operations are permitted.) Unique values can be used in conjunction with the inspect multibranch instruction studied in the next section. They are only appropriate for codes that can take on a fixed number of well-defined values—not as a way to program operations with many variants, a need better addressed by the object-oriented technique studied earlier and relying on inheritance, polymorphism, redeclaration, and dynamic binding.

Manifest constants are also available for strings, using double quotes, as in

   User_friendly_error_message: INTEGER is “Go get a life!”

with special characters again using the % codes. It is also possible to declare manifest arrays using double angle brackets:

   <<1, 2, 3, 5, 7, 11, 13, 17, 19>>

This example is an expression of type ARRAY [INTEGER]. Manifest arrays and strings are not atomic but denote instances of the kernel library classes STRING and ARRAY, as can be produced by once functions.


Previous Table of Contents Next