TYPE point REAL x,y END TYPE TYPE,EXTENDS(point) :: point_3d REAL z END TYPEThe type
zcomponents. Additionally, it has a
pointcomponent which refers to the inherited part; this “parent component” is “inheritance-associated” with the inherited components, so that the
point%xcomponent is identical to the
xcomponent et cetera.
However, when extending a type it is not required to add any new components; for example,
TYPE,EXTENDS(point) :: newpoint END TYPEdefines a new type
newpointwhich has exactly the same components as point (plus the associated parent component). Similarly, it is no longer necessary for a type to contain any components:
TYPE empty_type END TYPEdeclares the extensible (but not extended) type
empty_typewhich has no components at all.
)variable can assume any type in the class of types consisting of
)and all extensions of typename.
REAL FUNCTION bearing(a) CLASS(point) a bearing = atan2(a%y,a%x) ENDThe function
bearingmay be applied to a
TYPE(point)object or to a
TYPE(point_3d)object, or indeed to an object of any type that is an extension of
SELECT TYPEconstruct provides both a means of testing the dynamic type of a polymorphic variable and access to the extended components of that variable.
CLASS(t) x ... SELECT TYPE(p=>x) TYPE IS (t1) ! ! This section is executed only if X is exactly of TYPE(t1), not an ! extension thereof. P is TYPE(t1). ! TYPE IS (t2) ! ! This section is executed only if X is exactly of TYPE(t2), not an ! extension thereof. P is TYPE(t2). ! CLASS IS (t3) ! ! This section is executed if X is of TYPE(t3), or of some extension ! thereof, and if it is not caught by a more specific case. P is CLASS(t3). ! END SELECTNote that ‘
SELECT TYPE(x)’ is short for ‘
CLASS(*)’ is an unlimited polymorphic variable. It has no type, but can assume any type including non-extensible types and intrinsic types (and kinds). Apart from allocation, deallocation and pointer assignment, to perform any operation on an unlimited polymorphic you first have to discover its type using
SELECT TYPE. For example:
CLASS(*),POINTER :: x CHARACTER(17),TARGET :: ch x => ch SELECT TYPE(x) TYPE IS (COMPLEX(KIND=KIND(0d0))) PRINT *,x+1 TYPE IS (CHARACTER(LEN=*)) PRINT *,LEN(x) END SELECTNote that in the case of
CHARACTERthe length must be specified as ‘
*’ and is automatically assumed from whatever the polymorphic is associated with.
In the case of a non-extensible (i.e.
SELECT TYPE cannot be used to discover the type; instead, an unsafe
pointer assignment is allowed, for example:
TYPE t SEQUENCE REAL x END TYPE CLASS(*),POINTER :: x TYPE(t),POINTER :: y ... y => x ! Unsafe - the compiler cannot tell whether X is TYPE(t).
The arguments must be objects of extensible types (though they need not be
.TRUE. if and only if both
B have the same dynamic type.
.TRUE. if and only if the dynamic type
A is the same as, or an extension of, the dynamic type of
Note that if
MOLD is an unallocated unlimited polymorphic
CLASS(*)), the result will be true regardless of the state of
The arguments are permitted to be unallocated or disassociated, but they are not permitted to be pointers with an undefined association status.
It is recommended that where possible these intrinsic functions be avoided, and
SELECT TYPE be used for type checking instead.
ALLOCATEstatement now accepts a type-spec; this can be used to specify the dynamic type (and type parameters, if any) of an allocation. The type-spec appears before the allocation list, and is separated from it by a double colon.
For example, if
T is an extensible type and
ET is an
CLASS(t),POINTER :: a(:) ALLOCATE(et::a(100))allocates
Ato have dynamic type
ET. Note that the type-spec in an
ALLOCATEstatement omits the
TYPEkeyword for derived types, similarly to the
An unlimited polymorphic object can be allocated to be any type including intrinsic types: for example
CLASS(*),POINTER :: c,d ALLOCATE(DOUBLE PRECISION::c) READ *,n ALLOCATE(CHARACTER(LEN=n)::d)allocates
Cto be double precision real, and
Dto be of type
Typed allocation is only useful for allocating polymorphic variables and
CHARACTER variables with deferred length (
For a non-polymorphic variable, the type-spec must specify the declared
type and, if it is type
CHARACTER but not deferred-length,
to have the same character length.
The character length must not be specifed as an asterisk
CHARACTER(LEN=*)) unless the allocate-object is a dummy argument
with an asterisk character length (and vice versa).
Finally, since there is only one type-spec it must be compatible with all the items in the allocation list.
ALLOCATEstatement now accepts the
SOURCE=specifier. The dynamic type and value of the allocated entity is taken from the expression in the specifier. If the derived type has type parameters (q.v.), the value for any deferred type parameter is taken from the source expression, and the values for other type parameters must agree. This is not just applicable to derived types: if the entity being allocated is type
CHARACTERwith deferred length (
LEN=:), the character length is taken from the source expression.
Only one entity can be allocated when the
SOURCE= specifier is used.
Note that when allocating an array the array shape is not taken from the
source expression but must be specified in the usual way.
If the source expression is an array, it must have the same shape
as the array being allocated.
CLASS(*),POINTER :: a,b ... ALLOCATE(a,SOURCE=b)The allocated variable
Awill be a “clone” of
B, whatever the current type of
Bhappens to be.
CONTAINSstatement. The default accessibility of type-bound procedures is public even if the components are private; this may be changed by using the
PRIVATEstatement after the
The name of the type-bound procedure is binding-name, and the name of
the actual procedure which implements it is procedure-name.
If the optional
=>procedure-name is omitted, the actual procedure
has the same name as the binding.
A type-bound procedure is invoked via an object of the type, e.g.
CALL variable(i)%tbp(arguments)Normally, the invoking variable is passed as an extra argument, the “passed-object dummy argument”; by default this is the first dummy argument of the actual procedure and so the first argument in the argument list becomes the second argument, etc. The passed-object dummy argument may be changed by declaring the type-bound procedure with the
)attribute, in which case the variable is passed as the named argument. The
PASSattribute may also be used to confirm the default (as the first argument), and the
NOPASSattribute prevents passing the object as an argument at all. The passed-object dummy argument must be a polymorphic scalar variable of that type, e.g.
When a type is extended, the new type either inherits or overrides each
type-bound procedure of the old type.
An overriding procedure must be compatible with the old procedure; in
particular, each dummy argument must have the same type except for the
passed-object dummy argument which must have the new type.
A type-bound procedure that is declared to be
be overridden during type extension.
When a type-bound procedure is invoked, it is the dynamic type of the variable which determines which actual procedure to call.
The other attributes that a type-bound procedure may have are
DEFERRED (the latter only for abstract types,
which are described later).
GENERIC :: generic_name => specific_name_1, specific_name_2, specific_name_3Generic type-bound procedures may also be operators or assignment, e.g.
GENERIC :: OPERATOR(+) => add_t_t, add_t_r, add_r_tSuch type-bound generic operators cannot have the
NOPASSattribute; the dynamic type of the passed-object dummy argument determines which actual procedure is called.
When a type is extended, the new type inherits all the generic type-bound procedures without exception, and the new type may extend the generic with additional specific procedures. To override procedures in the generic, simply override the specific type-bound procedure. For example, in
TYPE mycomplex ... CONTAINS PROCEDURE :: myc_plus_r => myc1_plus_r PROCEDURE,PASS(B) :: r_plus_myc => r_plus_myc1 GENERIC :: OPERATOR(+) => myc_plus_r, r_plus_myc END TYPE ... TYPE,EXTENDS(mycomplex) :: mycomplex_2 ... CONTAINS PROCEDURE :: myc_plus_r => myc2_plus_r PROCEDURE,PASS(B) :: r_plus_myc => r_plus_myc2 END TYPEthe type
mycomplex_2inherits the generic operator ‘
+’; invoking the generic (
+) invokes the specific type-bound procedure, which for entities of type
mycomplex_2will invoke the overriding actual procedure (
TYPE, ABSTRACT :: mytypeAn abstract type cannot be instantiated; i.e. it is not allowed to declare a non-polymorphic variable of abstract type, and a polymorphic variable of abstract type must be allocated to be a non-abstract extension of the type.
Abstract type may contain
DEFERRED type-bound procedures, e.g.
... CONTAINS PROCEDURE(interface_name),DEFERRED :: tbpnameNo binding (“
=> name”) is allowed or implied by a deferred procedure binding. The
interface_namemust be the name of an abstract interface or a procedure with an explicit interface, and defines the interface of the deferred type-bound procedure.
When extending an abstract type, the extended type must also be abstract unless it overrides all of the deferred type-bound procedures with normal bindings.
proc-component-attr-spec-list :: proc-decl-list
POINTERattribute is required.
Note that object-bound procedures have a passed-object dummy argument just
like type-bound procedures; if this is not wanted, the
attribute must be used (and this is required if the interface is implicit,
proc-interface is missing or is a type specification).
The following example demonstrates using a list of subroutines with no arguments.
TYPE action_list PROCEDURE(),NOPASS,POINTER :: action => NULL() TYPE(action_list),POINTER :: next END TYPE TYPE(t),TARGET :: top TYPE(t),POINTER :: p EXTERNAL sub1,sub2 top%action = sub1 ALLOCATE(top%next) top%next%action = sub2 ... p => top DO WHILE (ASSOCIATED(p)) IF (ASSOCIATED(p%action)) CALL p%action p => p%next END DO