Passing a value for an optional fortran parameter that will return false for present()

I would like to find a way to get a fortran method to take some value for an optional parameter that will make the argument not appear to be present in the method that has been called.

Here is a reduced test case which distills the problem in the fortran code:

MODULE FortranOptional
  USE ISO_C_BINDING

CONTAINS
  SUBROUTINE optionaltest(scalar)
    REAL(8), OPTIONAL, INTENT(IN) :: scalar

    IF (PRESENT(scalar)) THEN
      print *, "scalar is present: ", scalar
    ELSE
      print *, "scalar is NOT present"
    END IF

  END SUBROUTINE optionaltest

  SUBROUTINE optionaltest_c(scalarC) BIND(C, NAME="optionaltest_c")
    REAL(C_DOUBLE), OPTIONAL, INTENT(IN) :: scalarC
    REAL(8) :: scalar

    IF (PRESENT(scalarC)) THEN
      print *, "scalarC is present: ", scalarC
      scalar = scalarC
    ELSE
      print *, "scalarC is NOT present"
      ! Can I do something here to make scalar appear not present in optionaltest()?
    END IF

    CALL optionaltest(scalar)
  END SUBROUTINE optionaltest_c
END MODULE FortranOptional

And the associated C++ test code:

extern "C"
{
void optionaltest_c(double*);
}

void testMethod()
{
    double v = 5.3;
    optionaltest_c(0);

    std::cout << "\n";

    optionaltest_c(&v);
}

Which produces:

scalarC is NOT present
scalar is present:    6.9118029901527309E-310

scalarC is present:    5.2999999999999998     
scalar is present:    5.2999999999999998     

Is there any way I can set the scalar variable based on the presence of scalarC that will make it appear to not be present when scalarC is not present?

Some constraints:

Upvotes: 2

Views: 898

Answers (1)

francescalus
francescalus

Reputation: 32366

In the subroutine optionaltest_c the variable scalar is a local one. As you note, a local variable has no concept of optional-ness.

For completeness, if it's just a matter of passing the optional dummy argument down from optionaltest_c to optionaltest, then

call optionaltest(scalarC)

would suffice. That is, an optional dummy argument may be an actual argument for a procedure where the corresponding dummy argument is also optional, regardless of its presence.

So, if instead you need to do some form of manipulation, what to do?1 I note that you have intrinsic assignment between the dummy argument and local variable.

Under Fortran 2008 there is a sensible option: have the local variable allocatable. If a variable is not allocated and is an actual argument for an optional non-allocatable dummy then it is treated as not present:

  subroutine optionaltest_c(scalarC) bind(C)
    type(type1), optional, intent(in) :: scalarC
    type(type2), allocatable :: scalar  ! Local, conformable with scalarC

    if (PRESENT(scalarC)) scalar=scalarC
    ...

    call optionaltest(scalar)
  end subroutine optionaltest_c

[You may need to provide alternative ways of allocating scalar and setting its value, depending on your compiler support.]

With scalarC present, scalar becomes allocated and has its value. Then on the call, the dummy argument is present. With scalarC not present, scalar is left not allocated and on the call the dummy argument is absent.

This works just as well for arrays as for scalars.

Now, I see that you mention gfortran 4.4.7, so it's possible this approach won't work. I'll let someone else answer with a specific way in that case, but this is perhaps still worth documenting for the benefit of others/after upgrade.


1 That may not be the case in this question if c_double has value 8, but we'll consider anyway.

Upvotes: 4

Related Questions