Both functions and subroutines can accept optional arguments. These are arguments that may be omitted by the caller, even if they’re specified in the procedure definition. To see optional arguments in action, let’s take our subroutine add from listing 3.13 and add an optional debug input parameter, as shown in listing 3.18. If this parameter is passed by the caller as the logical .true. value, we’ll print some debug statements to the screen, which can be helpful in diagnosing unexpected behavior in more complex programs.
Listing 3.18 Example of a subroutine using an optional input argument
subroutine add(a, b, res, debug)
integer, intent(in) :: a, b
integer, intent(out) :: res
logical, intent(in), optional :: debug ❶
if (present(debug)) then ❷
if (debug) then ❷
print *, 'DEBUG: subroutine add, a = ', a ❷
print *, 'DEBUG: subroutine add, b = ', b ❷
end if ❷
end if ❷
res = a + b
if (present(debug)) then ❷
if (debug) print *, & ❷
'DEBUG: subroutine add, res = ', res ❷
end if ❷
end subroutine add
❶ Marks the argument as optional using the “optional” attribute
❷ If debug is both present and .true., prints helpful diagnostics to the screen
The new argument to this subroutine, debug, is now declared with the optional attribute. Inside, we need to check whether the argument is passed or not. We do so by using an if block and present, a built-in function. This function returns .true. if its argument is present (passed in by the caller), and .false. otherwise. If not present, an optional argument must not be referenced inside the procedure in any way other than as an argument to present, or as an optional argument to another procedure. Because of this restriction, you now understand why I needed to make separate if tests for the presence of debug and for its value.
We can now invoke this subroutine in any of the following ways:
call add(3, 5, res)
call add(3, 5, res, .true.)
call add(3, 5, res, debug=.true.)
If invoked with the debug argument set to .true., the subroutine will emit the following to the screen:
DEBUG: subroutine add, a = 3
DEBUG: subroutine add, b = 5
DEBUG: subroutine add, res = 8
Although this kind of diagnostic printing may seem like overkill in this simple case, it can be a lifesaver when your programs become more complex.