In general, yes. It’s not hurting you here, but using explicit interfaces when passing procedures to other procedures can save you from one kind of nasty bug. As you have it now:
real function rk4(f, x, y, h)
implicit none
real, external :: f
...
procedure argument f doesn’t have an explicit interface. In other words, rk4 doesn’t know how many and what type of arguments can f take. It only knows that its result is real. So the compiler has to allow any real-valued function to be passed, and it also can’t check that you’re passing a function that is meaningful for rk4. The compiler is warning you that this can be a source of bugs.
To illustrate, suppose that in the module you also defined this function:
real function dy_bad(x)
real, intent(in) :: x
dy_bad = 2 * x
end function
I called it dy_bad to emphasize that it shouldn’t work when passed to rk4, because in rk4 you’re calling f with two input arguments, not one. If you now pass dy_bad to rk4, e.g.:
print *, rk4(dy_bad, 1., 1., 0.1)
not only will the code compile, but it will also run, and you may get a numerical result that is wrong but appears correct. Of course, here it’s obvious that dy_bad shouldn’t be passed to rk4, but the danger arises in larger programs where this kind of mistake could be easily made, either due to lack of attention or due to a typo.
Instead, define your procedure argument with an explicit interface like this:
real function rk4(f, x, y, h)
procedure(dy) :: f
...
Now if you try to pass dy_bad to rk4, you’ll get something like this when you try to compile the program:
$ gfortran test_explicit.f90
test_explicit.f90:32:15:
print *, rk4(dy_bad, 1., 1., 0.1)
1
Error: Interface mismatch in dummy procedure ‘f’ at (1): 'dy_bad' has the wrong number of arguments
Thanks to the explicit interface, the compiler can tell you exactly what’s wrong with this rk4 invocation.
A few other tips:
- You can state
implicit none once in the module, and let your functions defined in the module inherit the explicit typing rule.
- Define your procedures as
pure if they can be pure. It won’t change the behavior here but I think it’s a good practice. pure attribute prevents your procedures from causing side-effects elsewhere in the program. Another benefit is that if you use pure functions, you can’t pass procedure arguments with an implicit interface, so the compiler would force you to use explicit interface.