Chapter 4. Data Types

Table of Contents
4.1. Building the Data Environment for a Problem Solution
4.2. What Is Meant by type in Fortran
4.3. Intrinsic Data Types
4.4. Derived Types
4.5. Type Aliases
4.6. Enumeration and Enumerators
4.7. Structure Constructors
4.8. Array Constructors

Fortran was designed to give scientists and engineers an easy way to solve problems by using computers. Statements could be presented that looked like formulas or English sentences. For example, the following statement might be performing typical numeric calculations:

X = B + A * C

As another example, the following statement could specify that a certain action is to be taken based on a logical decision:

IF (LIMIT_RESULTS .AND. X .GT. XMAX) X = XMAX

And the following statement could be used to communicate the results of a calculation to a scientist or engineer in a meaningful way:

PRINT *, "CONVERGENCE REACHED"

Each of these statements performs a task that uses a different type of data:

Task 

Data Type

Calculating typical numeric results 

Numeric data

Making decisions 

Logical data

Explaining 

Character data

The preceding list shows the commonly needed data types, and the Fortran standard provides for them.

The Cray Fortran Compiler supports additional data types. This preserves compatibility with other vendor's systems. These additional types are as follows:

Note: The Fortran standard does not specify Cray pointer, Cray character pointer, or Boolean data types.

Anything provided by the language is intrinsic to the language. Types that are not intrinsic to the language can be specified by a programmer. The programmer-specified types are built of (or derived from) the intrinsic types and thus are called derived types. The Fortran data types are categorized in Figure 4-1.

Figure 4-1. Fortran Data Types

As the following list shows, the type of the data determines the operations that can be performed on it:

Data Type 

Operations

Real, complex, integer, Boolean 

Addition, subtraction, multiplication, division, exponentiation, negation, comparison, masking expressions

Logical 

Negation, conjunction, disjunction, and equivalence

Character 

Concatenation, comparison

User defined 

User defined

Cray pointer, Cray character pointer 

Addition, subtraction, and LOC(3i) function

The intrinsic types have the appropriate built-in (intrinsic) operations. You must define the operations performed on user-defined data types.

This chapter explains the Fortran data types. It describes each of the intrinsic types, and it explains derived types and the facilities provided by the language that allow you to define types and declare and manipulate objects of these types in ways that are analogous to the ways in which objects of the intrinsic types can be manipulated.

4.1. Building the Data Environment for a Problem Solution

When envisioning a computer solution to a problem you focus on the operations that must be performed and the order in which they must be performed. It is a good idea, however, to consider the variables you will need before you determine all the computational steps that are required. The variables that are chosen, together with their types and attributes, sometimes determine the course of computation, particularly when variables of user-defined type are involved.

4.1.1. Choosing the Type and Other Attributes of a Variable

There are several decisions to make about a variable in a program. If the variable is of an intrinsic type, the intended use of the variable will readily determine its type, making this an easy decision. While type is the most important attribute of a variable, there are other attributes. Certainly it is necessary to decide very early whether the variable is to be a single data object (a scalar) or an array. Fortran provides many new facilities for manipulating arrays as objects, making it possible to specify computations as straightforward array operations.

Because Fortran provides allocatable arrays and pointers, it is not necessary to decide at the outset how big an array must be. In fact, determining sizes can be postponed until the finished program is executed, when sizes can be read in as input or calculated. Setting aside space for an array can be deferred until the appropriate size needed for a particular calculation is known.

Another decision that can be made about a variable is its accessibility. Control of accessibility is a feature available in modules. If the variable is needed only within the module, then it can be kept private or hidden from other program units. This prevents it from being corrupted inadvertently. This feature can be used to make Fortran programs safer and more reliable.

In addition to type, dimensionality, dynamic determination, and accessibility, there are other attributes that can be applied to data objects. The attributes that are permitted depend on where and how the object is to be used; for example, there are a number of attributes that can be applied only to subprogram arguments. Chapter 5, describes all of the attributes of data objects.

4.1.2. Choosing the Kind of a Variable of Intrinsic Type

After the type of a variable is decided, you may need to consider which kind of the type to use. Each of the intrinsic types can be specified with a kind parameter that selects a processor-dependent representation of objects of that type and kind. If no kind parameter is specified, the default kind is assumed.

Note: Depending on your hardware platform, the Cray Fortran Compiler may support more than one kind for each data type.

Fortran requires a processor to support at least two kinds for the real and complex types and at least one kind for the other three intrinsic types.

The Fortran data types are as follows:

  • Real. Programs with REAL and DOUBLE PRECISION declarations are not numerically portable across machine architectures with different word sizes. The Cray Fortran Compiler chooses a representation for the real type that is efficient on the target machine. For example, a representation that fits into 32 bits is used on machines with 32-bit words, and a representation that fits into 64 bits is used on machines with 64-bit words.

    A kind parameter gives you access to and control over the use of different machine representations of real values in order to make a program more portable. For example, a kind parameter in a REAL declaration can specify a required minimum precision, as follows:

    REAL(KIND=SELECTED_REAL_KIND(10,50)) :: REAL_VALUE

    When a program is run on a 32-bit machine, it uses two words to contain variable REAL_VALUE. When the same program (without any changes) is run on a 64-bit machine, one word is used to contain variable REAL_VALUE.

    Fortran treats double-precision real as a separate kind of real. There are two ways to declare real variables: one is with a REAL statement specifying a nondefault kind and the other is with a DOUBLE PRECISION statement.

  • Complex. Fortran uses a COMPLEX attribute with a nondefault kind parameter to specify double-precision complex.

  • Character. The Fortran standard's kind type parameter values allow a single character to occupy more than one byte. Since the Cray Fortran Compiler supports only the ASCII character set, there is no nondefault character kind.

  • Integer. Alternative representations of integer data provide an integer kind with a very large range. The Cray Fortran Compiler supports several integer kinds.

4.1.3. Choosing to Define a Type for a Variable

Sometimes it is easier to think about an essential element of a problem as several pieces of related data, not necessarily all of the same type. Arrays can be used to collect homogeneous data (all of the same type) into a single variable. A structure is a collection of nonhomogeneous data in a single variable. To declare a structure, it is first necessary to define a type that has components of the desired types. The structure is then declared as an object of this user-defined (or derived) type.

An example of objects declared to be of user-defined type was given in Section 2.3.1. It is repeated here. First a type, named PATIENT, is defined. Next, two structures, JOHN_JONES and SALLY_SMITH, are declared:

TYPE PATIENT
   INTEGER         PULSE_RATE
   REAL            TEMPERATURE
   CHARACTER *300  PROGNOSIS
END TYPE PATIENT

TYPE(PATIENT)     JOHN_JONES, SALLY_SMITH

Type PATIENT has three components, each of a different intrinsic type (integer, real, and character). In practice, a type of this nature probably would have even more components, such as the patient's name and address, insurance company, room number in the hospital, and so on. For purposes of illustration, three components are sufficient. JOHN_JONES and SALLY_SMITH are structures (or variables) of type PATIENT. A type definition indicates names, types, and attributes for its components; it does not declare any variables that have these components. Just as with the intrinsic types, a type declaration is needed to declare variables of this type. Because there is a type definition, though, any number of structures can be created that have the components specified in the type definition for PATIENT; subprogram arguments and function results can be of type PATIENT; there can be arrays of type PATIENT; and operations can be defined that manipulate objects of type PATIENT. Thus, the derived-type definition can be used merely as a way to specify a pattern for a particular collection of related but nonhomogeneous data; but, because the pattern is specified by a type definition, a number of other capabilities are available.