Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fortran 2003 / 2008: Elegant default arguments?

In fortran, we can define default arguments. However, if an optional argument is not present, it can also not be set. When using arguments as keyword arguments with default values, this leads to awkward constructs like

PROGRAM PDEFAULT 

  CALL SUB
  CALL SUB(3)

CONTAINS 
  SUBROUTINE SUB(VAL)
    INTEGER, OPTIONAL :: VAL
    INTEGER :: AVAL ! short for "actual val"

    IF(PRESENT(VAL)) THEN
       AVAL = VAL
    ELSE 
       AVAL = -1   ! default value 
    END IF

    WRITE(*,'("AVAL is ", I0)') AVAL
  END SUBROUTINE SUB

END PROGRAM PDEFAULT

Personally, I often ran into the problem of accidentially typing VAL instead of AVAL, i.e. the disconnect between the variable name in the interface, and the initialized value used in the code can introduce runtime bugs – let alone that this manner of initialization is rather verbose.

Is there some more elegant way of using optional arguments with a default value?

Example It would feel more natural to write something like

IF(NOT(PRESENT(VAL))) VAL = -1 

because it avoids the VAL vs AVAL confusion. But it isn't valid, presumably because Fortran passes arguments by reference and thus if VAL is not present in the CALL statement, no memory is associated with VAL and VAL = -1 would cause a segfault.

like image 398
kdb Avatar asked Jun 09 '16 10:06

kdb


3 Answers

You described the situation rather well. There is no other way I am aware off and that is standard conforming. The pattern with a local variable named similarly is what people often use. The other option is to just put if (present()) else everywhere, but that is awkward.

The point is that they are optional arguments, not default arguments. Fortran doesn't have default arguments. The may have been better, but that is not what the committee members have chosen in the 80s when preparing Fortran 90.

like image 61
Vladimir F Героям слава Avatar answered Nov 04 '22 13:11

Vladimir F Героям слава


While also looking into this, I found out that you can in fact do something like the proposed example using the OPTIONAL and VALUE attributes (at least with gfortran, not sure how different compilers might handle it). E.g.:

PROGRAM PDEFAULT 

  CALL SUB
  CALL SUB(3)

CONTAINS 
  SUBROUTINE SUB(VAL)
    INTEGER, OPTIONAL,VALUE :: VAL

    IF(.NOT. PRESENT(VAL)) VAL = -1 ! default value

    WRITE(*,'("VAL is ", I0)') VAL
  END SUBROUTINE SUB

END PROGRAM PDEFAULT

This was implemented in version 4.9 of gfortran. And here's the relevant explanation in the documentation for argument passing conventions:

For OPTIONAL dummy arguments, an absent argument is denoted by a NULL pointer, except for scalar dummy arguments of type INTEGER, LOGICAL, REAL and COMPLEX which have the VALUE attribute. For those, a hidden Boolean argument (logical(kind=C_bool),value) is used to indicate whether the argument is present.

I also found this discussion interesting as historical context.

Maybe somebody more knowledgeable might have comments on whether doing this is a bad idea (aside from being compiler dependent), but at least at face value it seems like a nice workaround.

Note that this behavior is not part of the Fortran standard, and depends on the implementation of a given compiler. For example, the example code segfaults when using ifort (version 16.0.2).

like image 8
Gabe Avatar answered Nov 04 '22 13:11

Gabe


The Fortran standard lib (https://github.com/fortran-lang/stdlib) provides a function called optval that is used in stdlib_logger for example:

subroutine add_log_file( self, filename, unit, action, position, status, stat )
    ...
    character(*), intent(in), optional :: action
    ...
    character(16)  :: aaction
    ...
    aaction = optval(action, 'write')
    ...
end subroutine add_log_file

So their way of representing the "actual" value is a prepended a.

IMHO, I like the option with an appended _, since the optional values are visually marked as such in the call signature.

like image 3
greeeeeeen Avatar answered Nov 04 '22 15:11

greeeeeeen