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"))