Fortran 2003

Type-bound procedures

The procedure portion of a derived type definition allows you to bind specific procedures, generic interfaces, and final subroutines to a type.

Syntax of a type-bound procedure

The syntax of the type-bound procedure portion of a derived type definition is as follows:

Read syntax diagramSkip visual syntax diagram                          .----------------------.
                          V                      |
>>-CONTAINS--+---------+----+-specific_binding-+-+-------------><
             '-PRIVATE-'    +-generic_binding--+
                            '-final_binding----'
 

CONTAINS
For more information see CONTAINS
PRIVATE
You can only specify a PRIVATE statement if the type definition is within the specification part of a module.
specific_binding
Binds a procedure to the type, or specifies a deferred binding in an abstract type. See Specific binding
generic_binding
Defines a generic interface. See Generic binding
final_binding
Defines a list of final subroutines. See Final binding

You can identify a procedure using a binding name in the scope of the type definition, or an operator for a generic binding. The binding name is the name of a procedure of the type name and is referred to in the same way as a component of a type. For a specific binding, this name is the binding_name. For a generic binding whose generic specification is generic_name, this name is the generic_name. A final binding, or a generic binding whose generic specification is not generic_name, has no binding name.

Specific binding

Syntax of a specific_binding

The form of specific binding is:

Read syntax diagramSkip visual syntax diagram>>-PROCEDURE--+----------------------+-------------------------->
              '-(--interface_name--)-'
 
>--+-----------------------+--binding_name---------------------->
   +-,--attribute_list--::-+
   '-::--------------------'
 
>--+--------------------+--------------------------------------><
   '-=>--procedure_name-'
 
interface_name
defines the interface for the procedure. The interface_name must be the name of an abstract interface or of a procedure that has an explicit interface. If you specify an interface_name, you must not specify a procedure_name. An interface-name can appear if and only if the binding has the DEFERRED attribute
attribute
A binding can have one or more attributes, called binding attributes. The same binding attribute cannot appear more than once for the same binding. The list of binding attributes that you specify in an attribute_list includes:
PASS
Defines the passed-object dummy argument of the procedure.
NOPASS
Indicates that the procedure has no passed-object dummy argument. If the interface of the binding has no dummy argument of the type being defined, use NOPASS. PASS and NOPASS can not both be specified for the same binding.
access_spec
Is PUBLIC or PRIVATE.
NON_OVERRIDABLE
Prevents a binding from being overridden in an extended type. You must not specify NON_OVERRIDABLE for a binding with the DEFERRED attribute.
DEFERRED
Marks the procedure as deferred. Deferred bindings must only be specified for derived type definitions with the ABSTRACT attribute. A procedure with the DEFERRED binding attribute must specify an interface_name. An overriding binding can have the DEFERRED attribute only if the binding it overrides is deferred. The NON_OVERRIDABLE and DEFERRED binding attributes must not both be specified for the same procedure. See Abstract types and deferred bindings and Procedure overriding for more information.
binding_name
is the name of a binding of a type.
procedure_name
defines the interface for the procedure as well as the procedure to be executed when the procedure is referenced. The procedure_name must be the name of an accessible module procedure or an external procedure that has an explicit interface. If neither =>procedure_name nor interface_name appears, the procedure_name is the same as the binding_name. If =>procedure_name appears, you must specify the double-colon separator and an interface_name must not be specified.

Passed-object dummy arguments

A passed-object dummy argument applies to a type-bound procedure, or a procedure pointer component.

The passed-object dummy argument must be a scalar, nonpointer, nonallocatable dummy data object with the same declared type as the type being defined. The dummy argument must be polymorphic if and only if the type being defined is extensible.

In the example of a type-bound procedure with a specific binding, the type POINT contains a type-bound procedure with a specific binding. LENGTH is the type-bound procedure and POINT_LENGTH is the name of a module procedure.

Example of a type-bound procedure with a specific binding

TYPE :: POINT
   REAL :: X, Y
   CONTAINS
      PROCEDURE, PASS :: LENGTH => POINT_LENGTH
END TYPE POINT
...

The module-subprogram-part of the same module:

REAL FUNCTION POINT_LENGTH (A, B)

   CLASS (POINT), INTENT (IN) :: A, B
   POINT_LENGTH = SQRT ( (A%X - B%X)**2 + (A%Y - B%Y)**2 )

END FUNCTION POINT_LENGTH

Generic binding

Syntax of a generic_binding

The form of generic_binding is:

Read syntax diagramSkip visual syntax diagram>>-GENERIC--+------------+--::--generic_spec-------------------->
            +-,--PRIVATE-+
            '-,--PUBLIC--'
 
>--=>--binding_name_list---------------------------------------><
 

The generic_spec can be any of the following:

generic_name
OPERATOR(defined-operator)
The interface of each binding must be as specified in Defined operators.
ASSIGNMENT(=)
The interface of each binding must be as specified in Defined assignment.
dtio_generic_spec
The interface of each binding must be as specified in User-defined derived-type Input/Output procedure interfaces.

If the generic_spec is a generic_name, the generic_name cannot be the name of a nongeneric binding of the type. The same generic_spec may be used in several generic bindings within a single derived-type definition. In this case, every occurrence of the same generic_spec must have the same accessibility. Each binding name in the binding_name_list must be the name of a specific binding of the type.

When generic_spec is not a generic_name, each specific binding name in the binding_name_list must have the passed-object dummy argument. You can only specify one binding attribute, PRIVATE or PUBLIC. The following is an example of a generic binding where generic_spec is ASSIGNMENT(=).

! See example of a  procedure with a specific binding for definition of COLOR_POINT
TYPE, EXTENDS(color_point) :: point_info ! An extension of TYPE(COLOR_POINT)

   REAL :: color_code
   CONTAINS
   PROCEDURE, NOPASS:: get_color_code
   PROCEDURE :: info1 => color_to_info
   PROCEDURE :: point1 => point_to_info
   GENERIC :: ASSIGNMENT(=) => info1, point1
END TYPE point_info

CONTAINS
ELEMENTAL SUBROUTINE color_to_info(a, b)
   CLASS(point_info), INTENT(OUT) :: a
   TYPE(color_point), INTENT(IN):: b
   a%color_point = b
   a%color_code = get_color_code(b%color)
END SUBROUTINE
ELEMENTAL SUBROUTINE point_to_info(a, b)
   CLASS(point_info), INTENT(OUT) :: a
   TYPE(point), INTENT(IN):: b
   a%color_point = color_point(point=b, color=1)
   a%color_code = get_color_code(1)
END SUBROUTINE

Final binding

Syntax of a final_binding

A derived type is finalizable if the derived type has any final subroutines or any nonpointer, nonallocatable component with a type that is finalizable. A nonpointer data entity is finalizable if the type of the entity is finalizable. The form of final_binding is:

Read syntax diagramSkip visual syntax diagram>>-FINAL--+----+--final_subroutine_name_list-------------------><
          '-::-'
 
FINAL
Specifies a list of final subroutines. A final subroutine can be executed when a data entity of that type is finalized.
final_subroutine_name_list
A final_subroutine_name must be a module procedure with exactly one dummy argument. That argument must be nonoptional and must be a nonpointer, nonallocatable, nonpolymorphic variable of the derived type being defined. All length type parameters are assumed. The dummy argument cannot be INTENT(OUT). A final_subroutine_name must not be one previously specified as a final subroutine for that type. A final subroutine must not have a dummy argument with the same kind type parameters and rank as the dummy argument of another final subroutine of that type.

The following is an example of extended types with final subroutines:

Example of extended types with final subroutines

  MODULE m
   TYPE :: t1
    REAL a,b
   END TYPE
   TYPE, EXTENDS(t1) :: t2
    REAL,POINTER :: c(:),d(:)
    CONTAINS
    FINAL :: t2f
   END TYPE
   TYPE, EXTENDS(t2) :: t3
    REAL,POINTER :: e
    CONTAINS
    FINAL :: t3f
   END TYPE
   
   CONTAINS
   SUBROUTINE t2f(x) ! Finalizer for TYPE(t2)'s extra components
    TYPE(t2) :: x
      
    print *, 'entering t2f'  
    IF (ASSOCIATED(x%c)) then
     print *, ' c allocated, cleaning up'
     DEALLOCATE(x%c)
    end if 
    IF (ASSOCIATED(x%d)) then 
     print *, ' d allocated, cleaning up'
     DEALLOCATE(x%d)
    end if  
   END SUBROUTINE
   SUBROUTINE t3f(y) ! Finalizer for TYPE(t3)'s extra components
    TYPE(t3) :: y
      
    print *, 'entering t3f'
    IF (ASSOCIATED(y%e)) then
      print *, ' e allocated, cleanup up'
      DEALLOCATE(y%e)
    end if 
   END SUBROUTINE
END MODULE

program my_main
  call calc_span
end program

EXAMPLE: subroutine calc_span
  USE m
  TYPE(t1) x1
  TYPE(t2) x2
  TYPE(t3) x3
  
  allocate(x2%c(1:5), source=[1.0, 5.0, 10.0, 15.0, 20.0])
  allocate(x3%e, source=2.0)
  
  x2%c = x2%c + x3%e
  print *, 'calcs are=', x2%c

  ! Returning from this subroutine does
  ! nothing to x1. It is not finalizable
  ! the Fortran compiler places calls to the finalizer's at the
  ! end of a subroutine for the local variables of calc_span,
  ! as if the following calls were being made
  ! CALL t2f(x2)
  ! CALL t3f(x3)
  ! CALL t2f(x3%t2)
END SUBROUTINE

The output of the above program is:

calcs are= 3.000000000 7.000000000 12.00000000 17.00000000 22.00000000
entering t2f
c allocated, cleaning up
entering t3f
e allocated, cleanup up
entering t2f

Procedure overriding

If a nongeneric binding you specify in a type definition has the same binding name as a binding inherited from the parent type, then the binding you specify in the type definition overrides the binding inherited from the parent type.

The overriding binding and the overriden binding must satisfy the following conditions:

Example of procedure overriding

TYPE :: POINT
   REAL :: X, Y
   CONTAINS
   PROCEDURE, PASS :: LENGTH => POINT_LENGTH
END TYPE POINT
TYPE, EXTENDS (POINT) :: POINT_3D
   REAL :: Z
   CONTAINS
   PROCEDURE, PASS :: LENGTH => POINT_3D_LENGTH
END TYPE POINT_3D
...

The module-subprogram-part of the same module:

REAL FUNCTION POINT_LENGTH (A, B)
   CLASS (POINT), INTENT (IN) :: A, B
   POINT_LENGTH = SQRT ( (A%X - B%X)**2 + (A%Y - B%Y)**2 )
END FUNCTION POINT_LENGTH

REAL FUNCTION POINT_3D_LENGTH ( A, B )
   CLASS (POINT_3D), INTENT (IN) :: A
   CLASS (POINT), INTENT (IN) :: B
   SELECT TYPE(B)
      CLASS IS (POINT_3D)
      POINT_3D_LENGTH = SQRT( (A%X-B%X)**2 + (A%Y-B%Y)**2 + (A%Z-B%Z)**2 )
      RETURN
   END SELECT
   PRINT *, 'In POINT_3D_LENGTH, dynamic type of argument is incorrect.'
   STOP
END FUNCTION POINT_3D

If a generic binding specified in a type definition has the same generic_spec that does not satisfy the conditions as an inherited binding, it extends the generic interface and must satisfy the requirements specified in Unambiguous generic procedure references.

If a generic binding in a type definition has the same dtio_generic_spec as one inherited from the parent, it extends the generic interface for the dtio_generic_spec and must satisfy the requirements specified in Unambiguous generic procedure references.

A binding of a type and a binding of an extension of that type are correspond if:

End of Fortran 2003