User Defined Types and Portability
In some implementations of Ada, Integers are represented by 32-bit two's complement numbers, giving the range -2_147_483_648 .. 2_147_483_647. Other implementations use 16-bit two's complement Integers, giving the range -32_768 .. 32_767. However, some of the 16-bit implementations also provide a 32-bit type called Long_Integer.
Suppose we need a variable called Number to count from zero to one million. We could declare Number: Integer; for the 32-bit implementation, and change this to Number: Long_Integer; when we port the program to a machine running a 16-bit version that provides Long_Integer. However, we could also declare
type Counter is range 0 .. 1_000_000; Number : Counter;and both implementations of Ada will automatically select the appropriate internal representation for our type Counter! The 32-bit Ada will select Integer, and the 16-bit Ada will select Long_Integer. This gives us the advantage that no code has to be changed when the program is ported. Counter is called a user-defined type. Of course, we must use explicit type conversion to mix objects of type Counter with objects of other types.
Similarly, different implementations of Ada provide different representations for type Float, and some provide a type Long_Float. We can declare
type Real is digits 8; F : Real;and be certain that F will have at least 8 digits of accuracy on any machine that accepts this type declaration. A range constraint is optional.
User defined types also apply to fixed point numbers; these will be discussed in the section on More Records and Types.
It's possible to make a declaration that will be accepted by only some implementations of Ada. For example, if we declare
type X is digits 30 range 0.0 .. 100.0;some implementations of Ada might have to report that there's no available type that gives at least 30 digits of accuracy.
No language can give perfectly portable programs, but Ada truly advanced the state of the art in portability.
Derived Types
Derived types are created to prevent accidental mixing of objects. Unlike subtypes, derived types are distinct types. For example,
type No_Of_Apples is new Integer; type No_Of_Oranges is new Integer range 0 .. 100; NOA : No_Of_Apples; NOO : No_Of_Oranges; I : Integer; ... NOA := NOA + NOO; -- illegal NOA := NOA + NOA; NOA := NOA + I; -- illegal NOA := NOA + No_Of_Apples(I); NOA := NOA + No_Of_Apples(NOO);
A derived type is denoted by the reserved word new followed by an existing type like Integer. The operations that Ada knows for Integers, such as addition, are "inherited" by the derived types so that, for example, Ada knows how to add two objects of type No_Of_Oranges. As the examples above show, we can't mix types accidentally, but we can deliberately mix them by converting first.
In summary,
- Subtypes are usually created to provide range constraints:
subtype Day_Subtype is Integer range 1 .. 31;
- Derived types are usually created to prevent accidental mixing:
type No_Of_Apples is new Integer; type No_Of_Oranges is new Integer ... ;
- User-defined types are usually created to gain portability:
type Counter is range 0 .. 1_000_000; type Real is digits 8;
Question
type Meters is new Float; type Seconds is new Float; type Meters_Per_Second is new Float; ... function "*"(Left : in Meters_Per_Second; Right : in Seconds) return Meters is begin return Meters(Left) * Meters(Right); end "*"; function "*"(Left : in Seconds; Right : in Meters_Per_Second) return Meters is begin return Right * Left; end "*"; function "/"(Left : in Meters; Right : in Seconds) return Meters_Per_Second is begin return Meters_Per_Second(Left) / Meters_Per_Second(Right); end "/";The above program segment is an example of ...
No comments:
Post a Comment