For example:
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.
CLASS(
typename)
variable can assume any type in the class
of types consisting of TYPE(
typename)
and all extensions of
typename.
For example:
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)
.
SELECT TYPE
construct provides both a means of testing the dynamic
type of a polymorphic variable and access to the extended components of that
variable.
For example:
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(*)
’ 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
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).
EXTENDS_TYPE_OF(A,MOLD)
SAME_TYPE_AS(A,B)
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.
ALLOCATE
statement 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
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.
ALLOCATE
statement 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 CHARACTER
with 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.
For example,
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.
CONTAINS
statement.
The default accessibility of type-bound procedures is public even if the
components are private; this may be changed by using the PRIVATE
statement after the CONTAINS
.
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
statement, e.g.
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
).
ABSTRACT
, e.g.
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-list
NOPASS
, PASS
, PASS(
arg-name)
,
POINTER
, PRIVATE
or PUBLIC
, and
=> NULL()
’).
POINTER
attribute is required.
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