Like intrinsic data types, a Fortran 95/90 derived data type has a name, a set of associated values, a way to denote the values, and operations to manipulate and interpret these values. The names of the intrinsic data types are predefined, while the names of derived types are defined in derived-type definitions. A derived-type definition specifies the name of the type and the types of its components. A derived type can be resolved into "ultimate" components that are either of intrinsic type or are pointers. The set of values for a specific derived type consists of all possible sequences of component values permitted by the definition of that derived type. Structure constructors are used to specify values of derived types. Nonintrinsic assignment for derived-type entities must be defined by a subroutine with an ASSIGNMENT interface. Any operation on derived-type entities must be defined by a function with an OPERATOR interface. Arguments and function values can be of any intrinsic or derived type.
1 – Type Definitions
A derived-type definition specifies the name of a user-defined type
and the types of its components. It takes the following form:
TYPE [[, PRIVATE or PUBLIC] :: ] name
[PRIVATE or SEQUENCE]...
comp-def
[comp-def]...
END TYPE [name]
name Is the name of the derived type. It must not be
the same as the name of any intrinsic type, or
the same as the name of a derived type that can be
accessed from a module.
comp-def There must be at least one. It takes the following
form:
type [ [, attr-list] ::] comp [(a-spec)] [*char-len] [init_ex]
type Is a type specifier. It can be an intrinsic type
or a previously defined derived type. (If the POINTER
attribute follows this specifier, the type can also be
any accessible derived type, including the type
being defined.)
attr-list Is an optional list of component attributes POINTER
or DIMENSION. You can specify one or both attributes.
If DIMENSION is specified, it can be followed by an
array specification.
comp Is the name of the component being defined.
a-spec Is an optional array specification, enclosed in
parentheses. If POINTER is specified, the array is
deferred-shape; otherwise, it is explicit-shape.
In an explicit-shape specification, each bound must
be a constant scalar integer expression.
char-len Is an optional scalar integer literal constant; it
must be preceded by an asterisk (*). This parameter
can only be specified if the component is of type
CHARACTER.
init_ex Is an initialization expression or, for pointer
objects, =>NULL().
If a name is specified following the END TYPE statement, it must be
the same name that follows TYPE in the derived type statement.
Within a scoping unit, a derived-type name can only be defined
once. If the same derived-type name appears in a derived-type
definition in another scoping unit, it is treated independently.
A component name has the scope of the derived-type definition only.
Therefore, the same name can be used in another derived-type
definition in the same scoping unit.
Two entities can have the same derived type in the following cases:
o If they are both declared to be of the same derived type, and
the derived-type definition can be accessed from the same
module, the same scoping unit, or a host scoping unit.
o If they are both declared to be of the same derived type, and
the derived-type definition can be accessed from the same
scoping unit or a host scoping unit.
o If they are both declared in a derived-type definition
specifying SEQUENCE (they both have sequence type).
A sequence type can be defined in each scoping unit that needs
to access the type. Each derived-type definition must specify
the same name, the keyword SEQUENCE, and have components that
agree in order, name, and attributes. (No private components
are allowed in a sequence type.)
The same PRIVATE or SEQUENCE statements can only appear once in a
given derived-type definition.
If SEQUENCE is present, all derived types specified in component
definitions must be sequence types.
The PUBLIC or PRIVATE keywords can only appear if the derived-type
definition is in the specification part of a module.
The POINTER or DIMENSION attribute can only appear once in a given
comp-def.
A component is an array if the component definition contains a
DIMENSION attribute or an array specification. If the component
definition contains an array specification, the array bounds should
be specified there; otherwise, they must be specified following the
DIMENSION attribute.
If an initialization expression ("init_ex") appears for a
nonpointer component, the component (in any object of the type) is
initially defined with the value determined from the initialization
expression. The initialization expression is evaluated in the
scoping unit of the type definition.
The initialization expression overrides any default initial value
specified for the component. Explicit initialization in a type
declaration statement overrides default initialization.
If POINTER appears in the comp-def, the component is a pointer.
Pointers can have an association status of associated,
disassociated, or undefined. If no default initialization status
is specified, the status of the pointer is undefined. To specify
disassociated status for a pointer component, use =>NULL().
2 – Components
A reference to a component of a derived-type structure takes the
following form:
parent [%component [(s-list)]]... %component [(s-list)]
parent Is the name of a scalar or array of derived type.
The percent sign (%) is called a component selector.
component Is the name of a component of the immediately
preceding parent or component.
s-list Is a list of one or more subscripts. If the list
contains subscript triplets or vector subscripts,
the reference is to an array section.
Each subscript must be a scalar numeric expression
with a value that is within the bounds of its
dimension.
The number of subscripts in any s-list must equal
the rank of the immediately preceding parent or
component.
Each parent or component (except the rightmost) must be of derived
type.
The parent or one of the components can have nonzero rank (be an
array). Any component to the right of a parent or component of
nonzero rank must not have the POINTER attribute.
The rank of the structure component is the rank of the part (parent
or component) with nonzero rank (if any); otherwise, the rank is
zero. The type and type parameters (if any) of a structure
component are those of the rightmost part name.
The structure component must not be referenced or defined before
the declaration of the parent object.
If the parent object has the INTENT, TARGET, or PARAMETER
attribute, the structure component also has the attribute.
2.1 – Examples
The following example shows a derived-type definition with two
components:
TYPE EMPLOYEE
INTEGER ID
CHARACTER(LEN=40) NAME
END TYPE EMPLOYEE
The following shows how to declare a variable CONTRACT of type
EMPLOYEE:
TYPE(EMPLOYEE) :: CONTRACT
Note that both examples started with the keyword TYPE. The first
(initial) statement of a derived-type definition is called a
derived-type statement, while the statement that declares a
derived-type object is called a TYPE statement.
The following example shows how to reference component ID of parent
structure CONTRACT:
CONTRACT%ID
The following example shows a derived type with a component that is
a previously defined type:
TYPE DOT
REAL X, Y
END TYPE DOT
....
TYPE SCREEN
TYPE(DOT) C, D
END TYPE SCREEN
The following declares a variable of type SCREEN:
TYPE(SCREEN) M
Variable M has components M%C and M%D (both of type DOT); M%C has
components M%C%X and M%C%Y of type REAL.
The following example shows a derived type with a component that is
an array:
TYPE CAR_INFO
INTEGER YEAR
CHARACTER(LEN=15), DIMENSION(10) :: MAKER
CHARACTER(LEN=10) MODEL, BODY_TYPE*8
REAL PRICE
END TYPE
...
TYPE(CAR_INFO) MY_CAR
Note that MODEL has a character length of 10, but BODYTYPE has a
character length of 8. You can assign a value to a component of a
structure; for example:
MY_CAR%YEAR = 1985
The following shows an array structure component:
MY_CAR%MAKER
In the preceding example, if a subscript list (or substring) was
appended to MAKER, the reference would not be to an array structure
component, but to an array element or section.
Consider the following:
TYPE CHARGE
INTEGER PARTS(40)
REAL LABOR
REAL MILEAGE
END TYPE CHARGE
TYPE(CHARGE) MONTH
TYPE(CHARGE) YEAR(12)
Some valid array references for this type follow:
MONTH%PARTS(I) ! An array element
MONTH%PARTS(I:K) ! An array section
YEAR(I)%PARTS ! An array structure component
! (a whole array)
YEAR(J)%PARTS(I) ! An array element
YEAR(J)%PARTS(I:K) ! An array section
YEAR(J:K)%PARTS(I) ! An array section
YEAR%PARTS(I) ! An array section
The following example shows a derived type with a pointer component
that is of the type being defined:
TYPE NUMBER
INTEGER NUM
TYPE(NUMBER), POINTER :: BEFORE_NUM
TYPE(NUMBER), POINTER :: AFTER_NUM
END TYPE
A type such as this can be used to construct linked lists of
objects of type NUMBER.
The following example shows a private type:
TYPE, PRIVATE :: SYMBOL
LOGICAL TEST
CHARACTER(LEN=50) EXPLANATION
END TYPE SYMBOL
This type is private to the module. The module can be used by
another scoping unit, but type SYMBOL is not available.
The following example shows a derived-type definition that is
public with components that are private:
MODULE MATTER
TYPE ELEMENTS
PRIVATE
INTEGER C, D
END TYPE
...
END MODULE MATTER
In this case, components C and D are private to type ELEMENTS, but
type ELEMENTS is not private to MODULE MATTER. Any program unit
that uses the module MATTER can declare variables of type ELEMENTS,
and pass as arguments values of type ELEMENTS.
This design allows you to change components of a type without
affecting other program units that use the module.
If a derived type is needed in more than one program unit, the
definition should be placed in a module and accessed by a USE
statement whenever it is needed, as follows:
MODULE STUDENTS
TYPE STUDENT_RECORD
...
END TYPE
CONTAINS
SUBROUTINE COURSE_GRADE(...)
TYPE(STUDENT_RECORD) NAME
...
END SUBROUTINE
END MODULE STUDENTS
...
PROGRAM SENIOR_CLASS
USE STUDENTS
TYPE(STUDENT_RECORD) ID
...
END PROGRAM
Program SENIOR_CLASS has access to type STUDENT_RECORD, because it
uses module STUDENTS. Module procedure COURSE_GRADE also has
access to type STUDENT_RECORD, because the derived-type definition
appears in its host.
3 – Constructors
A structure constructor lets you specify scalar values of a derived
type. It takes the following form:
d-name (expr-list)
d-name Is the name of the derived type.
expr-list Is a list of expressions specifying component
values. The values must agree in number and
order with the components of the derived type.
If necessary, values are converted (according
to the rules of assignment), to agree with their
corresponding components in type and kind type
parameters.
A structure constructor must not appear before its derived type is
defined.
If a component of the derived type is an array, the shape in the
expression list must conform to the shape of the component array.
If a component of the derived type is a pointer, the value in the
expression list must evaluate to an object that would be a valid
target in a pointer assignment statement. (A constant is not a
valid target in a pointer assignment statement.)
If all the values in a structure constructor are constant
expressions, the constructor is a derived-type constant expression.
3.1 – Examples
Consider the following derived-type definition:
TYPE EMPLOYEE
INTEGER ID
CHARACTER(LEN=40) NAME
END TYPE EMPLOYEE
This can be used to produce the following structure constructor:
EMPLOYEE(3472, "John Doe")
The following example shows a type with a component of derived
type:
TYPE ITEM
REAL COST
CHARACTER(LEN=30) SUPPLIER
CHARACTER(LEN=20) ITEM_NAME
END TYPE ITEM
TYPE PRODUCE
REAL MARKUP
TYPE(ITEM) FRUIT
END TYPE PRODUCE
In this case, you must use an embedded structure constructor to
specify the values of that component; for example:
PRODUCE(.70, ITEM (.25, "Daniels", "apple"))