So regarding using MERGE(), it should not have optional arguments passed to it, but you recommend
METHOD I, but METHOD III will be available in F2023? I too would like to see some succinct way of specifying defaults for optional values; I have seen something like shown below proposed several times but cannot remember the arguments against them. Is there a current proposal for that?
METHOD I for large arrays would seem less appropriate because it would require a copy, so I might want to do a conditional if/else/endif but gets so long and ugly otherwise that it is one of the few places where I could use semi-colons to make them into one-line constructs as shown. And I dislike having to make the extra declarations of the local names but seems like the most portable standard method for some time to come.
program testit
! lots of optional arguments
call work()
call work(b=11.0)
call work(111.0,222.0,e=555.0)
contains
subroutine work(a, b, c, d, e)
real, optional :: a, b, c, d, e
real :: a_local, b_local, c_local, d_local, e_local
! METHOD I: Standard
! described method is standard
if (present(a)) then; a_local = a; else; a_local = 0.0; end if
if (present(b)) then; b_local = b; else; b_local = 0.0; end if
if (present(c)) then; c_local = c; else; c_local = 0.0; end if
if (present(d)) then; d_local = d; else; d_local = 0.0; end if
if (present(e)) then; e_local = e; else; e_local = 0.0; end if
! which, at least for standard types you could make a generic for.
! using a contained procedure for a real argument to illustrate
a_local = short_circuit(a)
b_local = short_circuit(b)
c_local = short_circuit(c, 10.0)
d_local = short_circuit(d, 20.0)
e_local = short_circuit(e, 30.0)
! METHOD II: WILL FAIL WITH SOME COMPILERS, PERHAPS ONLY WITH CERTAIN COMMAND SWITCHES
! issues with Fortran not short-circuiting and questions on
! whether undefined variable can be used in an executed statement.
! general concensus seems to be if just the variable is passed and
! not an expression with an operator or a function call it is OK,
! but good arguments against because MERGE() description does not
! indicate that the first argument is optional.
a_local = merge(a, 0.0, present(a))
b_local = merge(b, 0.0, present(b))
c_local = merge(c, 0.0, present(c))
d_local = merge(d, 0.0, present(d))
e_local = merge(e, 0.0, present(e))
! METHOD III: ! F 2023 PROBABLY NOT AVAILABLE YET
a_local = (present(a) ?a:0.0)
b_local = (present(b) ?b:0.0)
c_local = (present(c) ?c:0.0)
d_local = (present(d) ?d:0.0)
e_local = (present(e) ?e:0.0)
write(*,*) a_local, b_local, c_local, d_local, e_local
end subroutine work
function short_circuit(variable, default)
real, optional, intent(in) :: variable
real, optional, intent(in) :: default
real :: short_circuit
real :: default_local
if (present(default)) then
default_local = default
else
default_local = 0.0
end if
if (present(variable)) then
short_circuit = variable
else
short_circuit = default_local
end if
end function short_circuit
end program testit
The Future?
! one possible syntax for defining defaults
subroutine work(a=0.0,b=0.0,c=0.0,d=0.0,e=0.0)
real,intent(in),optional :: a,b,c,d,e
write(*,*) a, b, c, d, e
end subroutine work
! double-equal means to assign on each call instead of first instantiation,
! but used with parameters only if optional. Although having == and = have
! different meanings has historically been a problem with C, for example
subroutine work(a,b,c,d,e)
real,intent(in),optional :: a==0.0,b==0.0,c==0.0,d==0.0,e==0.0
a=a+1
write(*,*) a, b, c, d, e
end subroutine work