# A derived type containing a callback function as a member

**URL:** <https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364>\
**Category:** Help\
**Created:** [December 3, 2021, 6:34am UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364 "2021-12-03T06:34:20Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![zaikunzhang](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/zaikunzhang/32/785_2.png) [@zaikunzhang](https://fortran-lang.discourse.group/u/zaikunzhang)\
**Post date:** [December 3, 2021, 6:34am UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364/1 "2021-12-03T06:34:20Z")

</div>

I would like to define a derived type containing a callback function (subroutine) as a member.

For example, `problem` is a derived type that defines an optimization problem. It contains `objective`, `n`, and `x0` as the members. I imagine it will be implemented as follows.

```auto
type problem                                                                                                                         
       integer :: n                                                                                                                 
       real, allocatable :: x0(:)                                             
       procedure(FUN) :: objective ! Should this be a pointer?                         
end type problem 

```

Here, `objective` is a callback function (subroutine) with the following interface.

```auto
abstract interface                                                                                                                    
     subroutine FUN(x, f)                                                                                                              
     implicit none                                                                                                                     
     real, intent(in) :: x(:)                                                                                                     
     real, intent(out) :: f                                                                                                       
     end subroutine FUN                                                                                                                
end interface  

```

Now suppose that I would like to construct an instance of `problem`. In particular, I would like to set `objective` to the following subroutine.

```auto
subroutine qua(x, f) 
implicit none                                                                                                                     
real, intent(in) :: x(:)                                                                                                     
real, intent(out) :: f  
f = sum(x**2)     
end function 

```

How should this be implemented? Thank you very much.

---

<div class="post-metadata">

**Author:** ![Euler-37](https://avatars.discourse-cdn.com/v4/letter/e/b19c9b/32.png) [@Euler-37](https://fortran-lang.discourse.group/u/Euler-37)\
**Post date:** [December 3, 2021, 8:07am UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364/2 "2021-12-03T08:07:15Z")

</div>

```auto
procedure(FUN),pointer,nopass::objective=>NULL()

```

```auto
module test
    implicit none
    type problem
        integer :: n
        real, allocatable :: x0(:)
        procedure(FUN),nopass,pointer:: objective=>NULL() ! Should this be a pointer?
    end type problem

    abstract interface
    subroutine FUN(x, f)
        implicit none
        real, intent(in) :: x(:)
        real, intent(out) :: f
    end subroutine FUN
end interface

end module test
program main
    use test
    implicit none
    type(problem)::x
    procedure(fun)::qua
    real::y
    integer::i
    x%n=4
    x%x0=[(i,i=1,x%n)]
    x%objective=>qua
    call x%objective(x%x0,y)
    write(*,*)y
end program main

subroutine qua(x, f)
    implicit none
    real, intent(in) :: x(:)
    real, intent(out) :: f
    f = sum(x**2)
end subroutine qua

```

---

<div class="post-metadata">

**Author:** ![Arjen](https://avatars.discourse-cdn.com/v4/letter/a/b9bd4f/32.png) [@Arjen](https://fortran-lang.discourse.group/u/Arjen)\
**Post date:** [December 3, 2021, 8:35am UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364/3 "2021-12-03T08:35:46Z")

</div>

Note that with the nopass attribute you will have no access to the components of the object.

---

<div class="post-metadata">

**Author:** ![plevold](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/plevold/32/754_2.png) [@plevold](https://fortran-lang.discourse.group/u/plevold)\
**Post date:** [December 3, 2021, 11:28am UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364/4 "2021-12-03T11:28:18Z")

</div>

The typical way to do this would be to define an abstract type. For example:

```fortran
type, abstract :: problem_t
contains
    procedure(objective_i), deferred :: objective
end type

abstract interface
    pure real function objective_i(this, x) result(f)
        import problem_t
        class(problem_t), intent(in) :: this
        real, intent(in) :: x(:)
    end function
end interface

```

And then implement a concrete type that extends it:

```fortran
type, extends(problem_t) :: qua_problem_t
    integer :: n
    real, allocatable :: x0(:)
contains
    procedure :: objective
end type

contains

    pure real function objective_i(this, x) result(f)
        import problem_t
        class(problem_t), intent(in) :: this
        real, intent(in) :: x(:)
   
        ! You could also use n and x0 from qua_problem_t here
        f = sum(x**2)
    end function

```

Alternatively, Fortran actually has some kind of support for closures as well, though it’s not so obvious. Say you have a subroutine like this:

```fortran
module evaluator
    implicit none

    private
    public evaluate

    abstract interface
        real function func_i(x)
            real, intent(in) :: x
        end function
    end interface

contains

    real function evaluate(func, x) result(f)
        procedure(func_i) :: func
        real, intent(in) :: x

        f = func(x)
    end function
end module

```

To pass in a function `func(x) = a * x` where you specify `a` yourself you can do the following:

```fortran
program main
    use evaluator, only: evaluate
    implicit none

    real :: a

    a = 2
    write(*,*) 'func(3) = ', evaluate(func, 3.0)

    contains
        real function func(x) result(f)
            real, intent(in) :: x

            f = a * x
        end function
end program main

```

Notice here that `a` is defined in `main`, but accessible inside `func` due to the use of `contains` and because it is _not_ pure.

---

<div class="post-metadata">

**Author:** ![Beliavsky](https://avatars.discourse-cdn.com/v4/letter/b/ba8739/32.png) [@Beliavsky](https://fortran-lang.discourse.group/u/Beliavsky)\
**Post date:** [December 3, 2021, 12:43pm UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364/5 "2021-12-03T12:43:14Z")

</div>

> [@plevold](#):
>
> Notice here that `a` is defined in `main`, but accessible inside `func` due to the use of `contains` and because it is _not_ pure.

Thanks for the code example. The program compiles and runs, giving the same result with gfortran and ifort, even if `func` is declared `pure`. A `pure` function can access a variable such as `a` but cannot change it. I believe `func` cannot be declared [simple](https://fortran-lang.discourse.group/t/designating-simple-procedures/1644) (a feature of Fortran 202x) because it accesses `a`.

---

<div class="post-metadata">

**Author:** ![plevold](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/plevold/32/754_2.png) [@plevold](https://fortran-lang.discourse.group/u/plevold)\
**Post date:** [December 3, 2021, 12:46pm UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364/6 "2021-12-03T12:46:00Z")

</div>

You’re indeed right! Accessing the variable is no problem, only modifying it 👍

---

<div class="post-metadata">

**Author:** ![zaikunzhang](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/zaikunzhang/32/785_2.png) [@zaikunzhang](https://fortran-lang.discourse.group/u/zaikunzhang)\
**Post date:** [December 3, 2021, 1:42pm UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364/7 "2021-12-03T13:42:16Z")

</div>

Thank you @Euler-37 for the code.

What if I hope `problem` to have an initialization procedure that initializes `problem` according to a string indicating the problem name and an integer indicating the dimension? In other words, I hope to be able to initialize `problem` as follows.

```auto
type(problem) :: p
! The following should set `p%n` to `4`, `p%objective` to `qua`, and `p%x0` to `[1, 1, 1, 1]`. 
call p%intialize('qua', 4)   

```

Thank you very much!

---

<div class="post-metadata">

**Author:** ![zaikunzhang](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/zaikunzhang/32/785_2.png) [@zaikunzhang](https://fortran-lang.discourse.group/u/zaikunzhang)\
**Post date:** [December 3, 2021, 1:48pm UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364/8 "2021-12-03T13:48:17Z")

</div>

Thank you @plevold for the code. Your approach is very interesting, although it is a bit more difficult for me to understand compared to @Euler-37 's code. How do you compare the two approaches? Would you mind elaborating a bit on why your approach is more typical? Sorry for this naive question, but I have absolutely no experience in OOP with Fortran. Thank you very much!

---

<div class="post-metadata">

**Author:** ![Euler-37](https://avatars.discourse-cdn.com/v4/letter/e/b19c9b/32.png) [@Euler-37](https://fortran-lang.discourse.group/u/Euler-37)\
**Post date:** [December 3, 2021, 2:04pm UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364/9 "2021-12-03T14:04:10Z")

</div>

> [@zaikunzhang](#):
>
> What if I hope `problem` to have an initialization procedure that initializes `problem` according to a string indicating the problem name and an integer indicating the dimension? In other words, I hope to be able to initialize `problem` as follows.

I don’t know ,may be fortran doesn’t have this `eval`-like function.  
what we can do just `call p%init(qua,4)`,

```fortran
subroutine init(this,func,num)
    class(problem),intent(inout)::this
    procedure(FUN)::func
    integer,intent(in)::num
    this%objective=>func
    this%n=num
    !....
end subroutine init

```

---

<div class="post-metadata">

**Author:** ![zaikunzhang](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/zaikunzhang/32/785_2.png) [@zaikunzhang](https://fortran-lang.discourse.group/u/zaikunzhang)\
**Post date:** [December 3, 2021, 2:52pm UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364/10 "2021-12-03T14:52:24Z")

</div>

Thank you @Euler-37 . I tried this implementation, but compilers complain that `init` is not a member of `problem`, which agrees with how I understand the situation. Did I overlook something?

---

<div class="post-metadata">

**Author:** ![Euler-37](https://avatars.discourse-cdn.com/v4/letter/e/b19c9b/32.png) [@Euler-37](https://fortran-lang.discourse.group/u/Euler-37)\
**Post date:** [December 4, 2021, 2:06am UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364/11 "2021-12-04T02:06:45Z")

</div>

```auto
module test
    implicit none
    type problem
        integer :: n
        real, allocatable :: x0(:)
        procedure(FUN),nopass,pointer:: objective=>NULL()  
    contains
        procedure,pass::init !this is type bound procedure
    end type problem

    abstract interface
    subroutine FUN(x, f)
        implicit none
        real, intent(in) :: x(:)
        real, intent(out) :: f
    end subroutine FUN
end interface
contains
    subroutine init(this,func,num)
        class(problem),intent(inout)::this
        procedure(FUN)::func
        integer,intent(in)::num
        this%objective=>func
        this%n=num
        !....
    end subroutine init

end module test

```

---

<div class="post-metadata">

**Author:** ![everythingfunctional](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/everythingfunctional/32/176_2.png) [@everythingfunctional](https://fortran-lang.discourse.group/u/everythingfunctional)\
**Post date:** [December 4, 2021, 2:52am UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364/12 "2021-12-04T02:52:56Z")

</div>

> [@Euler-37](#):
>
> `procedure(FUN),pointer,nopass::objective=>NULL()`

This is exactly how the `test_case_t` types are implemented in vegetables ([see here](https://gitlab.com/everythingfunctional/vegetables/-/blob/main/src/vegetables/simple_test_case_m.f90)). This is how I would recommend implementing such a feature if:

- There is no other functionality that users of your type will need to provide
- They do not need to capture the values of variable inside the function at run time (i.e. actual closures, which Fortran doesn’t support, as once the enclosing scope is left, the variable no longer exists)
- You don’t know ahead of time all the function options your users will want to use

If the first point is not true, you may want to make your type abstract and have users extend it to provide their function. Or, define an abstract type that users must provide an instance of to your type. If the second point is not true, the previous suggestions may prove useful as well. If the last point is not true, it may be simpler to simply have a `select case` inside the procedure that makes use of the different options, and provide a set of `enumerator` values as the available options.

Basically, consider the next larger context (i.e. how this code will be used) when deciding what design strategy to employ.

---

<div class="post-metadata">

**Author:** ![zaikunzhang](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/zaikunzhang/32/785_2.png) [@zaikunzhang](https://fortran-lang.discourse.group/u/zaikunzhang)\
**Post date:** [December 4, 2021, 5:03am UTC](https://fortran-lang.discourse.group/t/a-derived-type-containing-a-callback-function-as-a-member/2364/13 "2021-12-04T05:03:33Z")

</div>

Thank @Euler-37 for the code.

In case it is useful to others, I summarize @Euler-37 's approach in the following code. It can be compiled by `gfortran`, `ifort`, `ifx`, `nagfor`, `flang`, AOCC `flang`, and `nvfortran`. Absoft Pro Fortran 22.0 supports F2003 fairly well, but cannot compile the code. Not surprisingly, the discontinued (F95) compilers `g95`, Lahey `lf95`, and `sunf95` all fail.

```auto
module fun_mod
implicit none
private
public :: FUN

abstract interface
    subroutine FUN(x, f)
    implicit none
    real, intent(in) :: x(:)
    real, intent(out) :: f
    end subroutine FUN
end interface

end module fun_mod

module test_mod

use fun_mod, only : FUN
implicit none
private
public :: PROBLEM

type PROBLEM
    integer :: n
    real, allocatable :: x0(:)
    procedure(FUN), nopass, pointer :: objective => null()
contains
    procedure, pass :: init ! Type-bound procedure
end type PROBLEM

contains

subroutine init(prob, probname, n)
implicit none
class(PROBLEM), intent(inout) :: prob
character(len=*), intent(in) :: probname
integer, intent(in) :: n
integer :: i
select case (probname)
case ('quad')
    prob % objective => quad
! There can be other cases ...
case default ! This is an error case. Should have some error-handling code. 
    prob % objective => null()
end select
prob % n = n
!allocate (prob % x0(n)) ! Not needed if the compiler supports the `F03` automatic allocation upon assignment
prob % x0 = [(i, i=1, n)]
end subroutine init

subroutine quad(x, f)
implicit none
real, intent(in) :: x(:)
real, intent(out) :: f
f = sum(x**2)
end subroutine quad

end module test_mod

program main

use test_mod, only : PROBLEM
implicit none

type(PROBLEM) :: p
real :: y

call p % init('quad', 4)
call p % objective(p % x0, y)

write (*, *) y

end program main

```
