Search code examples
fortransubroutineoption-typeplato

FORTRAN 95: OPTIONAL statement does not work (using FTN95 and Plato)


I am having a problem with the OPTIONAL statement in functions and subroutines with Fortran 95. Currently I am using Silverfrost's Plato and their FTN95 compiler (in "Release Win32" mode). After trying to implement the OPTIONAL statement in a more complex program I am writing, I created a very simple program to test it. Here is the code:

program TEST

implicit none
integer :: a=1, b=2

call Z(a,b)
call Z(a)
call Z(b)

end program TEST

subroutine Z(x,y)
implicit none
integer :: x
integer, optional :: y

if (present(y)) then
  write(*,*) x, y
  else
    write(*,*) x
endif

end subroutine Z

I expected the following result displayed on the screen:

1 2
1
2

Well, the code compiles, although I get a warning (673) that "SUBROUTINE Z has been called with too few arguments". After executing it, I get on my screen:

1 2

and then an "Access violation" error message. Can somebody understand what is wrong here?

Thanks a lot! Gilberto


Solution

  • Try putting the subroutine in a module, like so:

    module testoptional
    contains
        subroutine Z(x,y)
        implicit none
        integer :: x
        integer, optional :: y
    
        if (present(y)) then
          write(*,*) x, y
          else
            write(*,*) x
        endif
    
        end subroutine Z
    end module testoptional
    
    program TEST
        use testoptional
        implicit none
        integer :: a=1, b=2
    
        call Z(a,b)
        call Z(a)
        call Z(b)
    
    end program TEST
    

    Compiling and running then gives the expected result using gfortran and ifort.

    The problem is in how the main program knows (or guesses) the interface to Z(x,y). In the code you provide, although the main program and the subroutine are in the same file, there's nothing explicitly telling the main program the interface - the calling sequence, including argument counts, types, etc - of Z. The first call is to Z(a,b), so it infers there's a subroutine out there somewhere that takes two parameters; then it tries calling it with one parameter, which fails.

    Putting the subroutine in a module, then using the module (you could also use contains for a contained subroutine, or explicitly/manually providing the main program the interface using an interface block) then gives the main program the information it needs about the calling sequence - e.g., that there's an optional argument - and things work correctly.