Contents

2.2 STANDARD_INTEGERS package

Whenever it matters how many bits there will be in an integer, you should always specify the range yourself. If you try to do this locally in your program, then you might have some trouble interfacing with a library unit. Consider Figure 2, where package X has declared a 16-bit integer, and package Y has declared a 16-bit integer, and procedure P wants to use both packages at once. The types X.Whole_numbers and Y.Whole_numbers aren't the same type as Whole_numbers, so an Ada compiler will give an error similar to the one shown in Figure 2.

The problem can be solved by using the package STANDARD_INTEGERS, given in Listing 1. It declares some useful integer types of known ranges which can be shared by everybody. I didn't use a representation clause to specify the number of bits because I don't really care how many bits the computer uses. If a 32-bit computer finds it easier to use a whole 32-bit word to store an 8-bit value, that's fine with me. The important thing is to set the allowable range of values. Whether the computer has to use partial words or multiple words isn't of any concern unless it causes a performance limitation. (If I expect to run short of space or time, then I will make representation suggestions to the compiler, but under normal circumstances that isn't necessary.)

The SLIGHTLY_BETTER_COORDINATES package in Figure 3 shows how to use STANDARD_INTEGERS to solve the machine specific range problem.

2.2.1 Shared Data Types

Since Integer_16 is declared only once, any package or procedure that is compiled in the context of STANDARD_INTEGERS can use them. Figure 4 shows how packages X and Y and procedure P can share STANDARD_INTEGERS.Integer_16.

Engineering application programs often have one package that defines some data types that will be shared by many units. That's a consequence of the effect we saw in Figure 2, and it is an intentional feature of the Ada language. It's good to force the definition of a type to be in one place rather than allowing duplicate definitions to exist in several places. There's a chance that some, but not all, of the duplicate definitions would get changed when fixing a bug (creating even more bugs). The single definition of a shared data type insures that all modules will be working with the same kind of data. Putting all the type definitions in a single package makes them easy to find.

There is a danger, however, in creating one monster type definition package. Monsters usually try to take over the world, and type definition packages are no exception. If you put all your type definitions in one package, sooner or later practically every module depends on it. Then every module must be recompiled whenever a new type is added to the monster.

It is usually better to have several smaller type definition packages, and let the application program use whatever packages it needs. For example, you might have a package BRITISH_UNITS with data types Feet, Pounds, Seconds, and so on, that you have used on several projects. If you are assigned a new project that needs metric types as well, don't add the new metric types to BRITISH_UNITS. If you do, you will have to recompile everything that uses BRITISH_UNITS. Instead, write a new package METRIC_UNITS with types Meters and Newtons in it. Don't put Seconds in METRIC_UNITS because it already exists in BRITISH_UNITS, and Ada will try to keep BRITISH_UNITS.Seconds distinct from METRIC_UNITS.Seconds. If your program needs Newtons, Meters, and Seconds, compile it in the context of both BRITISH_UNITS and METRIC_UNITS.

Some data types are more naturally defined in a special package, rather than a general data types package. For example, it makes more sense to define Rectangular_points and Polar_points in POOR_COORDINATES (as was done in Figure 1) than it does to put them in BRITISH_UNITS and then compile POOR_COORDINATES in the context of BRITISH_UNITS. If POOR_COORDINATES was modified to use floating point types instead of Integer_32, then you would have to recompile BRITISH_UNITS and dozens (maybe hundreds) of modules that depend on BRITISH_UNITS. Leaving Rectangular_points and Polar_points in POOR_COORDINATES, allows you to change their definition without affecting many unrelated modules. You only need to recompile the few modules that depend on POOR_COORDINATES. That's a better approach to take.


Contents | Next ...