Modern Fortran - ProkopHapala/FireCore GitHub Wiki

Pass function as argument to other function

Module with generic function acepting another function as argument

module functional_mod2
  implicit none
  private
  public :: apply_function
contains
  function apply_function(f_ptr, x) result(y)
    real(8), intent(in) :: x
    real(8) :: y
    procedure(real(8) :: f_ptr) :: f_ptr       ! Procedure pointer as an argument
    y = f_ptr(x)  ! Call the function pointer
  end function apply_function
end module functional_mod2

Program using that generic function

program test_functional_pointer
  use functional_mod2
  implicit none
  real(8) :: x, result
  procedure(real(8) :: func_ptr), pointer :: f_ptr  ! Declare procedure pointer
  x = 2.0
  f_ptr => sine_function                  ! Point to a specific function (in this case sine_function)
  result = apply_function(f_ptr, x)       ! Apply the function using the procedure pointer
  print *, "Result from procedure pointer function: ", result
contains
  function sine_function(x) result(y)
    real(8), intent(in) :: x
    real(8) :: y
    y = sin(x)
  end function sine_function
end program test_functional_pointer

Named abstract Interface for a function in a module

Define named interface in module mod_interfaces.f90

module interface_mod
  implicit none
  abstract interface
    function func_real_real(x) result(y)
      real(8), intent(in) :: x   ! Input
      real(8) :: y               ! Output
    end function func_real_real
  end interface
end module interface_mod

use the interface in module mod_functional.f90

module functional_mod
  use interface_mod        ! Reuse the named interface
  implicit none
  public :: apply_function
contains
  function apply_function(f_ptr, x) result(y)
    real(8), intent(in) :: x
    real(8) :: y
    procedure(func_real_real) :: f_ptr        ! Use the named interface for the procedure pointer
    y = f_ptr(x)  ! Call the passed function
  end function apply_function
end module functional_mod

use both modules interface_mod and functional_mod in a program test_program.f90

program test_functional_pointer
  use functional_mod
  implicit none
  real(8) :: x, result
  procedure(func_real_real), pointer :: f_ptr     ! Use the named interface
  x = 2.0
  f_ptr => sine_function   ! Point to a specific function (in this case sine_function)
  result = apply_function(f_ptr, x)   ! Apply the function using the procedure pointer
  print *, "Result from procedure pointer function: ", result
contains
  function sine_function(x) result(y)
    real(8), intent(in) :: x
    real(8) :: y
    y = sin(x)
  end function sine_function
end program test_functional_pointer

compile like this

rm test_program mod_interfaces.o mod_functional.o
gfortran -c mod_interfaces.f90
gfortran -c mod_functional.f90
gfortran -o test_program mod_interfaces.o mod_functional.o test_program.f90
./test_program

Derived Class

Module which defines the base class and derived class

module shape_mod
  implicit none
  type, abstract :: Shape                   ! Define the abstract base class (type)
  contains
    procedure :: area => area_base          ! A deferred procedure for calculating area
  end type Shape
contains
  pure real(8) function area_base(this)     ! Base class area procedure (abstract, must be overridden)
    class(Shape), intent(in) :: this
    print *, "This is the base class method; should be overridden!"
    area_base = 0.0
  end function area_base
end module shape_mod
module circle_mod
  use shape_mod  ! Import the base class module
  implicit none
  type, extends(Shape) :: Circle             ! Define the derived class 'Circle' extending from Shape
    real(8) :: radius  ! Attribute specific to Circle
  contains
    procedure :: area => area_circle         ! Override the area procedure for Circle
  end type Circle
contains
  pure real(8) function area_circle(this)   ! Circle's overridden area function
    class(Circle), intent(in) :: this
    area_circle = 3.14159 * this%radius**2
  end function area_circle
end module circle_mod
program test_shapes
  use shape_mod                    ! Use the base class module
  use circle_mod                   ! Use the derived class module
  implicit none
  type(Circle) :: my_circle
  my_circle%radius = 2.0           ! Initialize the Circle object
  call compute_area(my_circle)     ! Call the polymorphic subroutine
contains
  subroutine compute_area(obj)           ! Subroutine to compute and print area (polymorphic argument)
    class(Shape), intent(in) :: obj      ! Accept any derived type of Shape
    real(8) :: result
    result = obj%area()                  ! Polymorphic dispatch: will call the correct `area` method
    print *, "The area is: ", result
  end subroutine compute_area
end program test_shapes