Derived types
are user-defined types that are constructed from entities of intrinsic
data types (see “Intrinsic
data types”)
or entities of previously defined derived types. For example, the
following is a definition of a derived type for manipulating coordinates consisting
of two real numbers:
TYPE coord REAL :: x,y END TYPE coord |
x and y are the components of the derived type coord.
The next statement declares two variables (a and b) of the derived type coord:
The next statement copies the values of a to b, as in any assignment statement:
The components of a and b are referenced as a%x, a%y, b%x, and b%y. By using the defined operation facility of Fortran 90,
it is possible to extend the standard operators to work with derived
types. For example, if the + and = operators were re-defined to operate on derived
type operands, the following statement
would be equivalent to
a%x = a%x + b%x; a%y = a%y + b%y |
The following sections describe:
The syntax of defining a derived
type
Referencing a structure component
Alignment of derived type objects
The last section provides an example program that illustrates
different features of derived types.
Defining
a derived type |
 |
The format for defining
a derived type is:
TYPE [[, access-spec] ::] type-name
[private-sequence-statement] ...
comp-definition-statement
[comp-definition-statement] ...
END TYPE [type-name]
- access-spec
is one of:
access-spec is allowed only if the definition appears within
a module. For more information about modules, see “Modules”. The PRIVATE and PUBLIC attributes are described in Chapter 10.
- type-name
is the name of the type being defined. type-name must not conflict with the intrinsic type names.
- private-sequence-statement
is a PRIVATE or SEQUENCE statement. The PRIVATE statement is allowed only if the definition appears
within a module. For more information about the SEQUENCE statement, see “Sequence
derived type”. Both statements are fully described in Chapter 10.
- comp-definition-statement
takes the form:
type-spec [[comp-attr-list]::]comp-decl
Notice that the syntax does not allow for initialization.
- comp-attr-list
can only contain
the DIMENSION and POINTER attributes. A component array without the POINTER attribute must have an explicit-shape specification with
constant bounds. If a component is of the same derived type as the
type being defined then the component must have the POINTER attribute. Both attributes are fully described
in Chapter 10.
- comp-declaration
takes the form:
comp-name [(array-spec)][*char-len]
where array-spec is an array specification, as described in “Array
declarations”; and char-len is used when comp-name is of type character to specify its length.
Sequence
derived type |
 |
As
shown in “Defining
a derived type”, the
SEQUENCE statement may appear in the definition of a derived
type. When storage for a variable of derived type is allocated,
the presence of the SEQUENCE statement in the definition of the derived type
causes the compiler to arrange all components in a storage sequence
that is the same as the order in which they are defined. Such a
derived type is called a sequence derived type.
A sequence derived
type may appear in a common block or in an equivalence set. The Standard
makes requirements about the type—numeric or character—of
the components in a sequence type. As an extension, HP Fortran
makes no restrictions on the types of the components other than
that the definition of the derived type must include the SEQUENCE statement.
Structure
component |
 |
A component
of a derived-type object may be referenced and used like any other
variable—in an expression, on the lefthand side of an assignment
statement, or as procedure argument. It may be a scalar, an array,
or itself a derived-type object. The component name has the same scope
as the derived-type object in which it is declared.
To
reference a structure component, use the form:
parent-name[%comp-name]...%comp-name
- parent-name
is a derived type. This part of a structure component
reference is the parent and is joined to comp-name by the component selector operator (%). The comp-name component to which the parent is joined on its immediate
right must be a component of parent-name. If parent-name has the INTENT, TARGET, or PARAMETER attribute, then the structure component being referenced—the
rightmost comp-name—also has that attribute.
- comp-name
is the name of a component. If more than one comp-name appears in a structure component reference, the reference
is to the rightmost comp-name. If more than one comp-name appears in the reference, each one (except the rightmost)
must be a derived-type object, and the comp-name to its immediate right must be one of its declared
components.
If parent-name and comp-name are arrays, each can be followed by a section-subscript-list enclosed in parentheses. See “Array
sections” for information about the syntax of
section-subscript-list. The Standard imposes certain restrictions on structure
component references that are array-valued, as described in “Array-valued
structure component references”.
If the
definition of a derived type contains a component that is of the
same derived type, the component must have the POINTER attribute. The following example defines the
derived type node, which includes a component (next) of the same derived type:
TYPE node ! for use in a singly linked list INTEGER :: value TYPE(node), POINTER :: next ! must have the POINTER attribute END TYPE node |
Declaring
a derived type-object |
 |
To declare
an object of derived type, use the TYPE statement, as follows:
TYPE (type-name) [[, attrib-list] :: ] entity-list
where type-name, attrib-list, and entity-list all have the same meaning as in a type declaration
statement that is used to declare an object of an intrinsic type;
see “Type
declaration for intrinsic types”.
Structure
constructor |
 |
A structure constructor
constructs a scalar value of derived type. The value is constructed
of a sequence of values for each component of the type. The syntax
of a structure constructor is:
type-name ( expression-list )
- type-name
is the name of the derived type. The name must have
been previously defined.
- expression-list
is a comma-separated list of expressions that must
agree in number, order, and rank with the components in type-name. For information about expressions, see “Expressions” and “Special
forms of expression”.
The following restrictions apply to the use of the structure
constructor:
If a component is of derived type,
an embedded structure constructor must be used to specify a value
for the derived-type component.
If a component is an array, an array constructor
must appear in expression-list that satisfies the array. For more information about
array constructors, see “Array
constructors”.
If a component is a pointer, the corresponding expression
in expression-list must evaluate to an allowable target.
Alignment
of derived-type objects |
 |
Derived type objects
have the same alignment as the component that has the most restrictive alignment
requirement. (This rule also applies to records.) To ensure natural
alignment, the compiler may add padding to each element in an array
of derived type.
The following illustrates the alignment of an array of derived
type. The definition of the derived type includes the SEQUENCE statement to ensure the order in which components
are laid out in memory is the same as in the definition. The SEQUENCE statement has no effect on alignment:
! definition of a derived type TYPE t SEQUENCE CHARACTER(LEN=7) :: c INTEGER(2) :: i2 REAL(8) :: r8 REAL(4) :: r4 END TYPE t ! declaration of an array variable of derived type TYPE (t), DIMENSION(5) :: ta |
Each element of t is allocated storage as shown in Table 3-4 “Example of structure storage”. The first component of t starts at an address that is a multiple of 8.
The four trailing padding bytes are necessary to preserve the alignment
of r8 in each element of the array.
Table 3-4 Example of structure storage
Component | Byte
offset | Length |
|---|
c | 0 | 7 |
i2 | 8 | 2 |
r8 | 16 | 8 |
r4 | 24 | 4 |
padding | 28 | 4 |
A
derived-type example |
 |
The example below,
traffic.f90, illustrates how to define a derived type, declare a
variable of the type, specify a value for the variable using the
structure constructor, pass the variable as an argument to another
procedure, and reference a structure component. The derived type
is defined in a module so that it can be made accessible by use
association.
For more information about modules and the USE statement, see “Modules”. The MODULE and USE statements are also described in Chapter 10.
Example 3-3 traffic.f90
 |
PROGRAM traffic ! Illustrates derived types: defines a derived type, declares an ! to array variable of derived type, uses a structure constructor ! assign to its components, and passes a component which is ! itself another derived type to a subprogram. ! Make the definition of the derived type called hours accessible ! to this program unit USE hours_def LOGICAL :: busy INTEGER :: choice ! Define another derived type that uses hours as a component TYPE hiway INTEGER :: rte_num TYPE(hours) :: busy_hours END TYPE hiway ! Declare an array of derived-type structures. TYPE(hiway), DIMENSION(3) :: route ! Use the structure constructor to specify values for each ! element of route route(1) = hiway(128, hours(.TRUE., .FALSE.)) route(2) = hiway(93, hours(.FALSE., .TRUE.)) route(3) = hiway(97, hours(.FALSE., .FALSE.)) PRINT *, 'What road do you want to travel?'PRINT *, '1. Rte. 128' PRINT *, '2. Rte. 93' PRINT *, '3. Rte 97' READ *, choice ! Pass the busy_hours component of the selected route to ! the function busy. IF (busy(route(choice)%busy_hours)) THEN PRINT *,’Heavy commute on rte.’, route(choice)%rte_num ELSE PRINT *,’Easy commute on rte.’, route(choice)%rte_num END IF END PROGRAM traffic LOGICAL FUNCTION busy(when) ! This function accepts a derived-type argument whose definition ! is defined in the module hours_def, made accessible here by ! use association. It returns .TRUE. or .FALSE., depending on ! on the value of the user-selected component of the argument. ! Make the definition of hours accessible to this function. USE hours_def TYPE(hours) :: when INTEGER :: choice PRINT *, 'When do you want to commute:' PRINT *, '1. Morning' PRINT *, '2. Evening' READ *, choice ! Find out if the route is busy at that time of day. IF (choice .EQ. 1) THEN busy = when%am ELSE busy = when%pm END IF END FUNCTION busy MODULE hours_def ! Define a derived type, which will be passed as an argument. TYPE hours LOGICAL :: am LOGICAL :: pm END TYPE hours END MODULE hours_def |
 |
Here are the command lines to compile and execute the program,
along with the output from a sample run:
$ f90 traffic.f90 $ a.out What road do you want to travel? 1. Rte. 128 2. Rte. 93 3. Rte 97 1 When do you want to commute: 1. Morning 2. Evening 1 Heavy commute on rte. 128 |