4 Basics types of Ada


Overview

This chapter introduces some of the types available in Ada as well as the operations available on and attributes of those types.


Types and subtypes


Scalar types

The predefined package Standard contains declarations for the standard types such as integer, float, character and boolean, as well as (notionally) defining the operations available on them.

All numeric literals belong to the class universal_integer or universal_float. Many of the attributes of the language (discussed later) also return a universal value. These universal types are compatible with any corresponding integer, float or fixed type.

E.g.

Subtypes can be created in Ada by restricting an existing type, by defining a new type based on an existing type or by enumerating the possible values of the type. A discussion of how to create these new types follows a look at the predefined types and their attributes.

The following operations are defined for all scalar types.


Integer types

The following are examples of integer declarations. Here the standard predefined integer type is used.

The following operators are also defined for all integer types.


Floating point types

The following are examples of floating point declarations. Floating point numbers have a relative error.

The following operators are also defined for all float types.


Fixed point types

The following are examples of fixed point declarations. Fixed point numbers have a bounded error, the absolute value of which is called the delta of the type.

The last example shows the usefulness of fixed point types - the ability to specify exactly how accurate the type should be. This allows control over facilities such as errors in rounding expressions, for example.


Enumeration types

An enumeration type is defined by listing all the possible values of the type.

Values of this type can be defined as follows:

Note that Ada can distinguish between enumeration literals from different types in most cases by examining the context. If this is not possible then type qualification must be used.

Enumeration types are useful to encode simple control codes used internally in a program.

There are two predefined enumerated types in the package STANDARD, the type character and the type boolean.


Booleans

The two values of boolean variables is true and false.

The following opeartors can be used with boolean types

Ada will not allow an unparenthesied expression to contain both and's and or's. This decreases the likelihood of misreading the intent of a complicated boolean expression.

E.g.

Usually when evaluating a boolean expression, the compiler is free to rearrange the evaluation of the terms as it sees fit. Both terms will be evaluated. For example in the following either term may be evaluated first.

However in some instances we wish to evaluate the terms in a defined order, and stop evaluations as soon as the value of the expression can be determined.

For example

Here we see if a is non zero before further evaluation.

The 'or else' statement is similar, only evaluation stops as soon as a term evaluates to true. This can be useful, for example, in a recursive search of a tree.

E.g.


Character

Ada83 initially had 7 bit characters. This restriction was eased before Ada95 arrived, but is still enforced by older compilers such as the Meridian Ada compiler. This creates problems when attempting to display graphic characters on a PC; generally you have to use integers to display characters above Ascii 127, using special routines supplied by the compiler vendor.


Ada95's Character type is based on Latin-1 and provides for 256 character positions. Ada95 also supports wide characters (ISO 10646 Basic Multilingual Plane (BMP)) and so all modern compilers can cope with 8 bit characters.

The 7 bit character set is described in the obsolecent package Standard.Ascii. The 8 bit character set is described in the package Standard. The package Ada.Characters.Latin_1 provides usable names for the characters.


Subtypes

We can restrict the range of values a variable can take by declaring a subtype with a restricted range of values (this corresponds to Pascal's user defined types). Any attempt to place an out-of-range value into a variable of a subtype results in an exception (a program controlled error reporting mechanism). In this way errors that the programmer has made can be discovered. The syntax for a subtype declaration is

Examples of declaring subtypes are given below.

Subtypes are compatable with their base types . They can be placed in the same place as any variable of the base type can. Also variables of different subtypes that are derived from the same base type are compatable.


Derived types

When subtypes are created they are still compatable with their base type. Sometimes we may wish to create distinctly new types that are not associated with the original type at all. This concept of type is very different to that provided by Pascal.

To do this we create a derived type from a parent type using the following syntax

A derived type is a completely new type and is incompatable with any other type, even those derived from the same parent type.

Derived types should be used when the modelling of a particular object suggests that the parent type is inappropriate, or you wish to partition the objects into distinct and unmixable classes.

Here employee_nos and account_nos are distinct and unmixable, they cannot be combined together without using explicit type conversion. Derived types inherit any operation defined on the base type. For example if a record was declared that had procedures push and pop, a derived type could be declared that would automatically have inherit the procedures.

Another important use of derived types is to produce portable code. Ada allows us to create a new level of abstraction, one level higher than, for example, the abstraction of Integer over a series of bits.

This is specified by using derived types, without a parent type.

For example,

Here the compiler is responsible for choosing an appropriately sized integer type. On a PC, it would be a 32 bit size, equivalent to long_integer. On a Unix workstation it would still be a 32 bit integer, but this would be equivalent to an integer. Letting the compiler choose frees the programmer from having to choose. Compiling it on a new host does not require changing the source code.


Type conversion

Despite the usefullness of being able to create distinct types, there are still occasions where we wish to convert from one type to another. One typical instance is to convert from one integer to float, or vice versa.

This causes the compiler to insert the appropriate code for type conversion (if needed) as part of the translation.

Do not confuse this with unchecked conversions (covered later) which often perform no internal representation transformation.

It needs to be stressed however that types are created distinct for a reason and that attempts to subvert the compiler's checks by performing type conversions should be either discouraged or performed only when semantically meaningfull.


Type Qualification

In some situations an expression's or value's type can be ambiguous.

For example,

Here we need to specify precisely what type is required. This is done with type qualification.

Type qualification does not change a value's type. It merely informs the compiler of what type the programmer thinks it should be.


Attributes

Ada also provides the ability to enquire about a type or object from within the code by using attributes. Some of the attributes for discrete types are

An example of the use of an attribute is

Here we achieve a maximal positive integer range without introducing any system dependent features.

In Ada83 non discrete types such as float, fixed and all their subtypes and derived types, the concepts of pred, succ and pos do not have meaning. In Ada95 they do. All other scalar attributes apply to the real types.


to the index...