Passing and using an optional mask within subroutine

Viewed 101

I pass an optional mask to a subroutine. Within this routine I then have many statements of the kind

...
if (present(Mask)) then
  where(Mask)
    y(:) = A(:)*B(:)
  end where
else
  y(:) = A(:)*B(:)
end if
...

This is very ugly in regards of code duplication. Are there any advices to do this in a better way? I have many statements like this in my code and I need to perform the operations on whole arrays.

Edit: At least a part of the problem can be solved through elemental functions. Because I have the same operations on the right side I can write

...
if (present(Mask)) then
  where(Mask)
    y(:) = multiply(A(:),B(:))
  end where
else
  y(:) = multiply(A(:),B(:))
end if
...
elemental real function multiply(a,b)
  real, intent(in) :: a,b
  multiply = a*b
end function

This way, I have at least a single place for the operations.

1 Answers

There is the option (pun intended) to no use optional arguments, and instead, write a generic interface. For example, instead of writing

subroutine bar(arg0, opt)
  integer, intent(inout) :: arg0
  integer, intent(in), optional :: opt
  arg0 = int(4 * atan(1.))
  if (present(opt)) arg0 = arg0 + opt
module foo

You can do

interface bar
  module procedure bar0
  module procedure bar1
end interface bar

contains

  subroutine bar0(arg0)
     integer, intent(inout) :: arg0
     arg0 = int(4 * atan(1.))
  end subroutine bar0

  subroutine bar1(arg0, opt)
     integer, intent(inout) :: arg0
     integer, intent(in) :: opt
     arg0 = arg0 + opt
  end subroutine bar1

end module foo

program bah
  use foo
  integer :: a0 = 1, a1 = 42
  call bar(a0)
  print *, a0
  call bar(a0, a1)
  print *, a0
end program bah

One advantage that you may gain from this approach is that bar0 and bar1 may allow a compiler to do a better job of optimizing the code. The if (present(opt)) construct may get in the way.

Related