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.