TYPE point REAL x,y END TYPE TYPE,EXTENDS(point) :: point_3d REAL z END TYPEThe type point_3d has x, y and z components. Additionally, it has a point component which refers to the inherited part; this “parent component” is “inheritance-associated” with the inherited components, so that the point%x component is identical to the x component 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 newpoint which 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_type which has no components at all.
REAL FUNCTION bearing(a) CLASS(point) a bearing = atan2(a%y,a%x) ENDThe function bearing may 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 TYPE(point).
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 ‘SELECT TYPE(x=>x)’.
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 CHARACTER the 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. BIND(C) or SEQUENCE) type, 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 polymorphic). SAME_TYPE_AS returns .TRUE. if and only if both A and B have the same dynamic type. EXTENDS_TYPE_OF returns .TRUE. if and only if the dynamic type of A is the same as, or an extension of, the dynamic type of MOLD. Note that if MOLD is an unallocated unlimited polymorphic (CLASS(*)), the result will be true regardless of the state of A.
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 that SELECT TYPE be used for type checking instead.
For example, if T is an extensible type and ET is an extension of T,
CLASS(t),POINTER :: a(:) ALLOCATE(et::a(100))allocates A to have dynamic type ET. Note that the type-spec in an ALLOCATE statement omits the TYPE keyword for derived types, similarly to the TYPE IS and CLASS IS statements.
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 C to be double precision real, and D to be of type CHARACTER with length N.
Typed allocation is only useful for allocating polymorphic variables and CHARACTER variables with deferred length (LEN=:). 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.
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 A will be a “clone” of B, whatever the current type of B happens to be.
PROCEDURE [[,binding-attr-list]::] binding-name [=>procedure-name]
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 PASS(argument-name) attribute, in which case the variable is passed as the named argument. The PASS attribute may also be used to confirm the default (as the first argument), and the NOPASS attribute 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. CLASS(t) self.
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 NON_OVERRIDABLE cannot 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 PUBLIC, PRIVATE, and 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 NOPASS attribute; 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_2 inherits the generic operator ‘+’; invoking the generic (+) invokes the specific type-bound procedure, which for entities of type mycomplex_2 will invoke the overriding actual procedure (myc2_plus_r or r_plus_myc2).
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_name must 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.
PROCEDURE( [proc-interface] ) , proc-component-attr-spec-list :: proc-decl-listwhere
Note that object-bound procedures have a passed-object dummy argument just like type-bound procedures; if this is not wanted, the NOPASS attribute must be used (and this is required if the interface is implicit, i.e. when 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