| Fortran Language Reference Manual, Volume 1 - S-3692-51 | ||
|---|---|---|
| Prev Section | Chapter 4. Data Types | Next Section |
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:
The components of the type
For any component that is of a derived type, the direct components of that derived type.
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:
In PARAMETER statements and in type declaration statements to define derived-type named constants
In DATA statements to specify initial values
As structure-valued operands in expressions
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.
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 | is |
| |
| type_attr_spec | is | access_spec | |
|
| or | ||
[data_component_part] | is | [ private_sequence_stmt ] ... component_def_stmt [ component_def_stmt ] ... | ||
| private_sequence_stmt | is |
| |
|
| or |
| |
component_def_stmt | is | data_component_def_stmt | ||
data_component_def_stmt | is |
| ||
| component_attr_spec | is |
| |
|
| or |
| |
|
| or |
| |
|
| or |
| |
| component_array_spec | is |
| |
|
| or |
| |
| component_decl | is |
| |
| end_type_stmt | is |
|
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:
A derived type with a component of a different derived type
A derived type with a pointer component
A derived type with a pointer component of the type being defined
A private type definition
A public type definition with private components
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) |
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.
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 |
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.
| Prev Section | Table of Contents | Title Page | Index | Next Section |
| Intrinsic Data Types | Up one level | Type Aliases |