I am not understanding the importance of CONTAINS statement in fortran 90
For example
PROGRAM BLABLA
IMPLICIT NONE
INTEGER :: i,j,k
i = 1; j = 1;k =1
PRINT *, i,j,k
CALL ABC(i,j,k)
PRINT *, i,j,k
CONTAINS
SUBROUTINE ABC(r,s,t)
IMPLICIT NONE
INTEGER, INTENT(IN) :: r,s
INTEGER, INTENT(OUT) :: t
t = r + s
END SUBROUTINE ABC
END PROGRAM BLABLA
and one by defining subroutines outside the main program. I understand for functions, one need to specify the type of the function, but for subroutines it is not required. I am interested in understanding whether there are any additional caveats in doing so?
PROGRAM BLABLA
IMPLICIT NONE
INTEGER :: i,j,k
i = 1; j = 1;k =1
PRINT *, i,j,k
CALL ABC(i,j,k)
PRINT *, i,j,k
END PROGRAM BLABLA
SUBROUTINE ABC(r,s,t)
IMPLICIT NONE
INTEGER, INTENT(IN) :: r,s
INTEGER, INTENT(OUT) :: t
t = r + s
END SUBROUTINE ABC
In both your first and second versions try changing the line
CALL ABC(i,j,k)
to
CALL ABC(i,j)
and see what happens, firstly at compile time and secondly at run time.
When you have done that, and reported back on your findings, I can turn this into a proper answer.
OK, so here's the answer, most of which you've already figured out:
In the old days, before Fortran 90, it was common for FORTRAN (everyone shouted the name in those days) programs to be compiled in separate 'units' (it still is). In your second version the program and the subroutine are in separate units and are compiled separately. There is no information available to the compiler to check that the call to the subroutine matches the subroutine signature -- that is left to the programmer to check. Call the subroutine incorrectly and almost anything can happen -- if you're lucky the program crashes or produces obviously erroneous results, if you're unlucky it produces not-obviously-erroneous-but-still-erroneous results.
If you include the source code for the subroutine in the scope of the program unit, and use the contains
section, as in your first version of your program, the compiler will create an interface for the subroutine and can check that any calls made to the subroutine are formally correct. Hence the failure to compile you discovered.
The other way to have the compiler generate the interface for subroutines, and these approaches work for functions too, is to put them into a module and use
the module in the program. You'll find many examples of how to do this in other Qs and As here on SO.
Putting the subroutine into a module isn't exactly the same as including it in a contains
section. In the contains
section the subroutine can use variables declared in the program without their being passed through the subroutine's argument list. This is rather frowned upon as poor programming practice but you do come across it in the wild.