Let’s look at the Brent’s method: https://github.com/jacobwilliams/opt-lib/blob/0ce2825f87d511bc33764e0aadd3f3061c9c8ca6/src/stdlib_root_core.F90#L1300

The function signature is:

```
subroutine brentq(me,ax,bx,fax,fbx,xzero,fzero,iflag)
class(brentq_solver),intent(inout) :: me
real(wp),intent(in) :: ax !! left endpoint of initial interval
real(wp),intent(in) :: bx !! right endpoint of initial interval
real(wp),intent(in) :: fax !! `f(ax)`
real(wp),intent(in) :: fbx !! `f(ax)`
real(wp),intent(out) :: xzero !! abscissa approximating a zero of `f` in the interval `ax`,`bx`
real(wp),intent(out) :: fzero !! value of `f` at the root (`f(xzero)`)
integer,intent(out) :: iflag !! status flag (`0`=root found, `-2`=max iterations reached)
```

Which to me looks very good except the first `me`

argument which is of type:

```
type,abstract,public :: root_solver
!! abstract class for the root solver methods
private
procedure(func),pointer :: f => null() !! user function to find the root of
real(wp) :: ftol = 0.0_wp !! absolute tolerance for `f=0`
real(wp) :: rtol = 1.0e-6_wp !! relative tol for x
real(wp) :: atol = 1.0e-12_wp !! absolute tol for x [not used by all methods]
integer :: maxiter = 2000 !! maximum number of iterations [not used by all methods]
contains
private
procedure,public :: initialize => initialize_root_solver !! initialize the class [must be called first]
procedure,public :: solve !! main routine for finding the root
procedure(root_f),deferred :: find_root !! root solver function. Meant to be
!! called from [[solve]], which handles some common
!! startup tasks. All these routines assume that
!! \( f(a_x) \) and \( f(b_x) \) have opposite signs.
procedure :: get_fa_fb
procedure :: converged
end type root_solver
type,extends(root_solver),public :: brentq_solver
!! brentq root solver
private
contains
private
procedure,public :: find_root => brentq
end type brentq_solver
```

So I personally would not like this API, because one has to first setup the derived type before calling the function. However, we can do both. We can refactor the `brent`

function as:

```
subroutine brentq(f,ftol,rtol,atol,maxiter,ax,bx,fax,fbx,xzero,fzero,iflag)
procedure(func),pointer :: f !! user function to find the root of
real(wp), intent(in) :: ftol !! absolute tolerance for `f=0`
real(wp), intent(in) :: rtol !! relative tol for x
real(wp), intent(in) :: atol !! absolute tol for x [not used by all methods]
integer, intent(in) :: maxiter = 2000 !! maximum number of iterations [not used by all methods]
real(wp),intent(in) :: ax !! left endpoint of initial interval
real(wp),intent(in) :: bx !! right endpoint of initial interval
real(wp),intent(in) :: fax !! `f(ax)`
real(wp),intent(in) :: fbx !! `f(ax)`
real(wp),intent(out) :: xzero !! abscissa approximating a zero of `f` in the interval `ax`,`bx`
real(wp),intent(out) :: fzero !! value of `f` at the root (`f(xzero)`)
integer,intent(out) :: iflag !! status flag (`0`=root found, `-2`=max iterations reached)
```

And then this is standalone and it will work. And then we can create a simple wrapper in the `brentq_solver`

class for those who prefer the OO interface.