4.4. Derived Types

Unlike the intrinsic types that are defined by the language, you must define derived types. These types have the same utility as the intrinsic types. For example, variables of these types can be declared, passed as procedure arguments, and returned as function results.

A derived-type definition specifies a name for the type; this name is used to declare objects of the type. A derived-type definition also specifies components of the type, of which there must be at least one. A component can be of intrinsic or derived type; if it is of derived type, it can be resolved into components, called ultimate components. An ultimate component is of intrinsic type and can be a pointer or can have the ALLOCATABLE attribute.

The direct components of a derived type are as follows:

If the type definition appears in a module, the type definition may contain the keywords PUBLIC or PRIVATE. Generally, entities specified in a module can be kept private to the module and will not be available outside the module. This is true of data objects, module subprograms, and type definitions. By default, entities specified in a module are available to any program unit that accesses the module; that is, they have PUBLIC accessibility by default. This default can be changed by inserting a PRIVATE statement ahead of the specifications and definitions in the module. Individual entities can be specified to have either the PUBLIC or PRIVATE attribute regardless of the default. For a type definition, this can be accomplished by a PUBLIC or PRIVATE specifier in the TYPE statement of the type definition. The keyword PRIVATE can be used in two ways in type definitions in a module. One way makes the entire type private to the module; the other way allows the type name to be known outside the module, but not the names or attributes of its components. A separate PRIVATE statement that mentions the type name or a PRIVATE specifier in the TYPE statement of the type definition provides the first of these. An optional PRIVATE statement inside the type definition provides the second. See Section 4.4.1, for examples of a private type and a public type with private components.

A type definition can contain a SEQUENCE statement. The Fortran standard allows a processor to rearrange the components of a derived type in any convenient order. However, if a SEQUENCE statement appears inside the type definition, the type is considered to be a sequence type. In this case, the processor must allocate storage for the components in the declared order so that structures declared to be of the derived type can appear in COMMON and EQUIVALENCE statements. See Section 4.4.1, for an example of a sequence type.

The ALLOCATABLE component attribute allows you to assign storage for components of a derived type after the derived type is declared. You may do this because the storage size for the component is not known or needed at the time the type is declared. The ALLOCATE command assigns storage to the component when needed, and the DEALLOCATE command removes it.

Default initialization is specified for a component of an object of derived type when initialization appears in the component declaration. The object is initialized as specified in the derived type definition even if the definition is private or inaccessible. Default initialization applies to dummy arguments with INTENT (OUT) and function return values. Unlike explicit initialization, default initialization does not imply that the object has the SAVE or STATIC attribute. If a component has default initialization, it is not required that default initialization be specified for other components of the derived type.

A derived type has a set of values that is every combination of the permitted values for the components of the type. The language provides a syntax for constants of the intrinsic types; it provides a somewhat similar mechanism, called a structure constructor, to specify a value for a derived type. A constructor can be used in the following places:

User-defined functions and subroutines must be used to define operations on entities of derived type. Thus, the four properties of the intrinsic types (possession of a name, a set of values, a set of operations, and a syntactic mechanism to specify constant values) are also provided for derived types.

4.4.1. Derived Type Definition

A type definition gives a derived type a name and specifies the types and attributes of its components. A derived type definition begins with a TYPE statement, ends with an END TYPE statement, and has component declarations in between. The following example defines type PATIENT:

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

The format of a derived_type_def is as follows:

TYPE [ [, type_attr_spec_list ] :: ] type_name
    [ private_sequence_stmt ] ...
   component_def_stmt [ component_def_stmt ] ...
   END TYPE [ type_name ]

A derived-type definition is defined as follows:

Table 4-17.

 

derived_type_def

is

derived_type_stmt
  [data_component_part]
end_type_stmt

 

derived_type_stmt

is

TYPE [ [, type_attr_spec_list ] :: ] type_name

 

type_attr_spec

is

access_spec

 

 

or

BIND(C)

[data_component_part]

is

[ private_sequence_stmt ] ... component_def_stmt [ component_def_stmt ] ...

 

private_sequence_stmt

is

PRIVATE

 

 

or

SEQUENCE

component_def_stmt

is

data_component_def_stmt

data_component_def_stmt

is

type_spec [ [ , component_attr_spec_list  ] :: ]  component_decl_list 

 

component_attr_spec

is

access_spec

 

 

or

ALLOCATABLE

 

 

or

POINTER

 

 

or

DIMENSION (component_array_spec)

 

component_array_spec

is

explicit_shape_spec_list

 

 

or

deferred_shape_spec_list

 

component_decl

is

component_name [(component_array_spec )] [* char_length ]
   [ component_initialization ]

 

end_type_stmt

is

END TYPE [ type_name ]

The name of the derived type must not be the same as any intrinsic type or locally accessible name in the same class; it has the scope of local names declared in the scoping unit, which means that it is accessible by use or host association in other scoping units. A component name has the scope of the type definition only; another type definition in the same scoping unit may specify the same component name. For more information about local entities and scope, see the Fortran Language Reference Manual, Volume 2.

If the END TYPE statement is followed by a name, it must be the name specified in the TYPE statement.

A type can be defined only once within a scoping unit.

A PRIVATE statement must not appear more than once in a type definition.

A SEQUENCE statement must not appear more than once in a type definition

For access_spec, specify PRIVATE, PUBLIC, or PROTECTED. For more information about component accessibility, see Section 5.6.1.1.

The keywords PUBLIC and PRIVATE can appear only if the definition is in the specification part of a module.

The BIND(C) attribute allows the derived type to interoperate with a C object of struct type. Refer toFortran Language Reference Manual, Volume 2 for information about C interoperability.

There must be at least one component definition statement in a type definition.

A component that is a derived type and that uses the ALLOCATABLE attribute cannot be initialized . That is, if ALLOCATABLE appears in component_attr_spec_list, do not use component_initialization.

If SEQUENCE is present, all derived types specified as components must also be sequence types.

All derived types specified in component definitions must also have the BIND(C) attribute.

No component attribute can appear more than once in a specified component definition statement.

A component can be declared to have the same type as the type being defined only if it has the POINTER attribute.

Components that use the ALLOCATABLE attribute cannot be initialized.

component_attr_spec_list cannot use the POINTER and ALLOCATABLE attribute at the same time.

The component_array_spec must be a deferred-shape array if the POINTER or ALLOCATABLE attribute is present; otherwise, it must be an explicit-shape array.

If a component_array_spec does not use the ALLOCATABLE or POINTER attribute, it must be an explicit_shape_spec_list.

An array component without the POINTER or ALLOCATABLE attribute must be specified with an explicit-shape specification where the bounds are integer constant expressions.

If a component is of type character with a specified length, the length must be an integer constant specification expression. If the length is not specified, it is 1.

If component_initialization is specified, a double colon separator (::) must appear before the component_decl_list.

If => appears in a component_initialization, the POINTER attribute must appear in the component_attr_spec_list. If = appears in a component_initialization, the POINTER attribute cannot appear in the component_attr_spec_list.

If initialization_expr appears for a nonpointer component, that component in any object of the type is initially defined or becomes defined as specified in Fortran Language Reference Manual, Volume 2, with the value determined from initialization_expr. The initialization_expr is evaluated in the scoping unit of the type definition. The evaluation rules are the same as if the component were a variable=initialization_expr. If component_name is a type for which default_initialization is specified for a component, the default_initialization specified by initialization_expr overrides the default initialization specified for that component. Explicit initialization in a type declaration statement overrides default initialization. An object of a type with default initialization must not be specified in a DATA statement.

The following example shows a derived-type definition with four components (three integer and one character):

TYPE COLOR
   INTEGER :: HUE, SHADE, INTENSITY
   CHARACTER(LEN = 30) :: NAME
END TYPE COLOR

The following is a format for declaring variables of derived type:

TYPE (type_name) [ [ , attribute_list ] :: ] entity_list

For example, variables of type COLOR can be declared as follows:

TYPE(COLOR) MY_FAVORITE
TYPE(COLOR) RAINBOW(7)
TYPE(COLOR), DIMENSION (100) :: SELECTIONS

The object MY_FAVORITE is a structure. The objects RAINBOW and SELECTIONS are arrays of structures.

Note that the initial statement of a type definition and the statement used to declare objects of derived type both begin with the keyword TYPE. The initial statement of a type definition is called a derived-type statement, and the statement used to declare objects of derived type is called a TYPE statement. The type name in a derived-type statement is not enclosed in parentheses, whereas the type name in a TYPE statement is.

A component of a structure is referenced using a percent sign, as in the following template:

parent_structure % component_name

Examples:

MY_FAVORITE % HUE
RAINBOW(3) % NAME

The following examples show definitions of derived types. Each example illustrates a different aspect of a type definition:

Example 1: A derived type can have a component that is of a different derived type. Type WEATHER in the following example has a component of type TEMPERATURES.

TYPE TEMPERATURES
   INTEGER :: HIGH, LOW
END TYPE TEMPERATURES

TYPE WEATHER
   CHARACTER(LEN = 32) :: CITY
   TYPE(TEMPERATURES) :: RANGE(1950:2050)
END TYPE WEATHER

TYPE(WEATHER) WORLDWIDE(200)

WORLDWIDE is an array of type WEATHER. Components of an element of the array are referenced as follows:

WORLDWIDE(I)%CITY = "Nome"
WORLDWIDE(I)%RANGE(1990)%LOW = -83

Example 2: A derived type can have a component that is a pointer, as follows:

TYPE ABSTRACT
   CHARACTER(LEN = 50) TITLE
   INTEGER NUM_OF_PAGES
   CHARACTER, POINTER :: TEXT(:)
END TYPE ABSTRACT

Any object of type ABSTRACT will have three components: TITLE, NUM_OF_PAGES, and TEXT. TEXT is a pointer to an array of character strings, each of which is of length one. The array size is determined during program execution. The space for the target of TEXT can be allocated, or TEXT can be pointer-assigned to existing space. For information on the ALLOCATE statement, see Section 6.5.1. For information on pointer assignment, see Section 7.5.3.

Example 3: A derived type can have a pointer component that is of the type being defined. This is useful in creating linked lists and trees, as follows:

TYPE LINK
   REAL VALUE
   TYPE(LINK), POINTER :: PREVIOUS
   TYPE(LINK), POINTER :: NEXT
END TYPE LINK

Example 4: A type definition in a module can be kept private to the module, as follows:

TYPE, PRIVATE :: FILE
   INTEGER DRAWER_NO
   CHARACTER(LEN = 20) FOLDER_NAME
   CHARACTER(LEN = 5) ACCESS_LEVEL
END TYPE FILE

When a module that contains this type definition is accessed by another scoping unit, the type FILE is not available.

Example 5: A type definition can be public while its components are kept private, as follows:

MODULE COORDINATES
   TYPE POINT
      PRIVATE
      REAL X, Y
   END TYPE POINT
      ...
END MODULE COORDINATES

In a program unit that uses module COORDINATES, variables of type POINT can be declared. Values of type POINT can be passed as arguments. If the program unit is a function, a value of type POINT can be returned as the result. However, the internal structure of the type (its components) is not available. If the type POINT is changed to the following, no other program unit that uses COORDINATES will need to be changed:

TYPE POINT
   PRIVATE
   REAL RHO, THETA
END TYPE POINT

If a subprogram dummy argument is of derived type, the corresponding actual argument must be of the same type. There are two ways in which objects in different scoping units can be declared to be of the same type. Two data entities have the same type if they are declared with reference to the same type definition. The definition can appear in a module that is accessed or, in the case of an internal or module procedure, in the host scoping unit.

MODULE SHOP
   TYPE COMPONENT
      CHARACTER(LEN = 20) NAME
      INTEGER CATALOG_NUM
      REAL WEIGHT
   END TYPE COMPONENT
   TYPE(COMPONENT) PARTS(100)
CONTAINS
   SUBROUTINE GET_PART(PART, NAME)
      TYPE(COMPONENT) PART
      CHARACTER(LEN = *) NAME
      DO I = 1, 100
         IF (NAME .EQ. PARTS(I)%NAME) THEN
            PART = PARTS(I)
            RETURN
         END IF
      END DO
      PRINT *, "Part not available"
      PART%NAME = "none"
      PART%CATALOG_NUM = 0
      PART%WEIGHT = 0.0
   END SUBROUTINE GET_PART
      . . .
END MODULE SHOP

PROGRAM BUILD_MACHINE
   USE SHOP
   TYPE(COMPONENT) MOTOR(20)
   TOTAL_WEIGHT = 0.0
   CALL GET_PART(MOTOR(1), "VALVE")
   IF (MOTOR(1)%WEIGHT .NE. 0) THEN
      TOTAL_WEIGHT = TOTAL_WEIGHT + MOTOR(1)%WEIGHT
   ELSE
      . . .
   ENDIF
   . . .
END PROGRAM BUILD_MACHINE

Module procedure GET_PART has access to the type COMPONENT because the type definition appears in its host. Program BUILD_MACHINE has access to the type because it uses module SHOP. This allows a variable of the type, such as MOTOR(1), to be passed as an actual argument.

The other way to declare data entities in different scoping units to be of the same type is provided for programmers who choose not to use a module. Instead of a single type definition in the module, a sequence type can be defined in each of the scoping units that need access to the type. Each of the type definitions must specify the same name; the SEQUENCE property; have no private components; and have components that agree in order, name, and attributes. If this is the case, data entities declared in any of these scoping units to be of the named type are considered to be of the same type. In the following, program BUILD_MACHINE is restated to illustrate the differences between the two ways:

PROGRAM BUILD_MACHINE
   TYPE COMPONENT
      SEQUENCE
      CHARACTER(LEN = 20) NAME
      INTEGER CATALOG_NUM
      REAL WEIGHT
   END TYPE COMPONENT
   TYPE(COMPONENT) PARTS, MOTOR(20)
   COMMON /WAREHOUSE/ PARTS(100)
   TOTAL_WEIGHT = 0.0
   CALL GET_PART(MOTOR(1), "VALVE")
   IF (MOTOR(1)%WEIGHT .NE. 0) THEN
      TOTAL_WEIGHT = TOTAL_WEIGHT + MOTOR(1)%WEIGHT
   ELSE
      . . .
   ENDIF
      . . .
END PROGRAM BUILD_MACHINE
SUBROUTINE GET_PART(PART, NAME)
   TYPE COMPONENT
      SEQUENCE
      CHARACTER(LEN = 20) NAME
      INTEGER CATALOG_NUM
      REAL WEIGHT
   END TYPE COMPONENT
   TYPE(COMPONENT) PART, PARTS
   CHARACTER(LEN = *) NAME
   COMMON /WAREHOUSE/ PARTS(100)
   DO I = 1, 100
      IF (NAME .EQ. PARTS(I)%NAME) THEN
         PART = PARTS(I)
         RETURN
      END IF
   END DO
   PART%NAME = "none"
   PART%CATALOG_NUM = 0
   PART%WEIGHT = 0.0
   PRINT *, "Part not available"
END SUBROUTINE GET_PART
   . . .

In this example, type COMPONENT in program BUILD_MACHINE and type COMPONENT in subroutine GET_PART are the same because they are sequence types with the same name; have no private components; and have components that agree in order, name, and attributes. This allows variables of the type to appear in COMMON and be passed as arguments. Note that this example is less concise, particularly if more procedures need to access the type definition, and therefore may be more error prone than the previous example.

Type COMPONENT is a sequence type because its definition contains a SEQUENCE statement. If all of the ultimate components of a sequence type are of type default integer, default real, double-precision real, default complex, or default logical, and are not pointers, the type is a numeric sequence type. An object of numeric sequence type can be equivalenced to default numeric objects.

If all of the ultimate components of a sequence type are of type character and are not pointers, the type is a character sequence type. An object of character sequence type may be equivalenced to character objects.

A pointer component of a derived type can have as its target an object of that derived type. The type definition can specify that in objects declared to be of this type, such a pointer is default initialized to disassociated. In the following example, type NODE is created and is used to construct linked lists of objects of type NODE:

TYPE NODE
   INTEGER :: VALUE
   TYPE (NODE), POINTER :: NEXT_NODE => NULL ( )
END TYPE

Initialization need not be specified for each component of a derived type. For example:

TYPE DATE
   INTEGER DAY
   CHARACTER (LEN = 5) MONTH
   INTEGER :: YEAR = 1994     ! PARTIAL DEFAULT INITIALIZATION
END TYPE DATE

In the following example, the default initial value for the YEAR component of TODAY is overridden by explicit initialization in the type declaration statement:

TYPE (DATE), PARAMETER :: TODAY = DATE (21, "Feb.", 1995)

4.4.2. Derived Type Values

The set of values of a derived type consists of all combinations of the possibilities for component values that are consistent with the components specified in the type definition.

4.4.3. Derived Type Operations

Any operation involving a derived-type entity must be defined explicitly by a function with an OPERATOR interface. Assignment, other than the intrinsic assignment provided for entities of the same derived type, must be defined by a subroutine with an ASSIGNMENT interface. See the Fortran Language Reference Manual, Volume 2, for a description.

Suppose it is desirable to determine the number of words and lines in a section of text. The information is available for each paragraph. A type named PARAGRAPH is defined as follows:

TYPE PARAGRAPH
   INTEGER NUM_WORDS, NUM_LINES
   CHARACTER(LEN = 30) SUBJECT
END TYPE PARAGRAPH

Suppose that it is now desirable to define an operator for adding the counts associated with the paragraphs. The following OPERATOR interface is required for the function that defines the addition operation for objects of type PARAGRAPH:

INTERFACE OPERATOR (+)
   MODULE PROCEDURE ADDP
END INTERFACE

The following definition of addition for objects of type PARAGRAPH adds the words and lines, but it does nothing with the component SUBJECT because that would have no useful meaning:

TYPE(PARAGRAPH) FUNCTION ADDP(P1, P2)
   TYPE(PARAGRAPH) P1, P2
   INTENT(IN) P1, P2
   ADDP%NUM_WORDS = P1%NUM_WORDS + P2%NUM_WORDS
   ADDP%NUM_LINES = P1%NUM_LINES + P2%NUM_LINES
END FUNCTION ADDP

If the following variables were declared, the expression BIRDS+BEES would be defined and could be evaluated in the module subprogram as well as any program unit accessing the module:

TYPE(PARAGRAPH) BIRDS, BEES

4.4.4. Syntax for Specifying Derived-type Constant Expressions

When a derived type is defined, a structure constructor for that type is defined automatically. The structure constructor is used to specify values of the type. It specifies a sequence of values, one for each of the components of the type. A structure constructor whose values are all constant expressions is a derived-type constant expression. (This is why a derived-type value is formed by a constructor. There is no such thing as a structure constant; there are only structure constructors, some of which may be constant expressions.) A named constant of user-defined type can be assigned such a value. Structure constructors are described in Section 4.7.

A component of a derived type can be an array. In this case a mechanism called an array constructor is used to specify that component of the type. Array constructors are described in Section 4.8, and a general discussion of arrays can be found in Section 6.4.