Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Fortran preserve the value of internal variables through function and subroutine calls?

After much painful debugging, I believe I've found a unique property of Fortran that I'd like to verify here at stackoverflow.

What I've been noticing is that, at the very least, the value of internal logical variables are preserved across function or subroutine calls.

Here is some example code to illustrate my point:

PROGRAM function_variable_preserve
IMPLICIT NONE

CHARACTER(len=8) :: func_negative_or_not ! Declares function name
INTEGER :: input
CHARACTER(len=8) :: output

input = -9

output = func_negative_or_not(input)
WRITE(*,10) input, " is ", output
10 FORMAT("FUNCTION: ", I2, 2A)

CALL sub_negative_or_not(input, output)
WRITE(*,20) input, " is ", output
20 FORMAT("SUBROUTINE: ", I2, 2A)

WRITE(*,*) 'Expected negative.'


input = 7
output = func_negative_or_not(output)
WRITE(*,10) input, " is ", output

CALL sub_negative_or_not(input, output)
WRITE(*,20) input, " is ", output

WRITE(*,*) 'Expected positive.'

END PROGRAM function_variable_preserve

CHARACTER(len=*) FUNCTION func_negative_or_not(input)
IMPLICIT NONE

INTEGER, INTENT(IN) :: input
LOGICAL :: negative = .FALSE.

IF (input < 0) THEN
    negative = .TRUE.
END IF

IF (negative) THEN
    func_negative_or_not = 'negative'
ELSE 
    func_negative_or_not = 'positive'
END IF

END FUNCTION func_negative_or_not

SUBROUTINE sub_negative_or_not(input, output)
IMPLICIT NONE

INTEGER, INTENT(IN) :: input
CHARACTER(len=*), INTENT(OUT) :: output
LOGICAL :: negative = .FALSE.

IF (input < 0) THEN
    negative = .TRUE.
END IF

IF (negative) THEN
    output = 'negative'
ELSE 
    output = 'positive'
END IF

END SUBROUTINE sub_negative_or_not

This is the output:

FUNCTION: -9 is negative
SUBROUTINE: -9 is negative
 Expected negative.
FUNCTION:  7 is negative
SUBROUTINE:  7 is negative
 Expected positive.

As you can see, it appears that once the function or subroutine is called once, the logical variable negative, if switched to .TRUE., remains as such despite the initialization of negative to .FALSE. in the type declaration statement.

I could, of course, correct this problem by just adding a line negative = .FALSE. after declaring the variable in my function and subroutine.

However, it seems very odd to me that this be necessary.

For the sake of portability and code reusability, shouldn't the language (or compiler maybe) require re-initialization of all internal variables each time the subroutine or function is called?

like image 548
EMiller Avatar asked Aug 18 '10 05:08

EMiller


People also ask

What is the difference between function and subroutine in Fortran?

A function must return a single value, and can be invoked from within expressions, like a write statement, inside an if declaration if (function) then , etc. A subroutine does not return a value, but can return many values via its arguments and can only be used as a stand-alone command (using the keyword call ).

What does a Fortran subroutine return?

Return (in Subroutines) A return statement in a subroutine instructs Fortran to terminate the subroutine and return to the main program at the point where it departed. Thus it works like a stop statement in the main program, halting the program prematurely before the final end statement.

What's the difference between subroutine and function?

Functions and subroutines operate similarly but have one key difference. A function is used when a value is returned to the calling routine, while a subroutine is used when a desired task is needed, but no value is returned.

What is the standard term for a variable or value that is passed from one subroutine to another?

Each value you place between the round brackets is known as an argument (or sometimes a parameter). The arguments must match. So if you have set up your Sub line to accept two arguments then you must pass two arguments in on the calling line, otherwise you'll get an error.


2 Answers

To answer your question: Yes Fortran does preserve the value of internal variables through function and subroutine calls.

Under certain conditions ...

If you declare an internal variable with the SAVE attribute it's value is saved from one call to the next. This is, of course, useful in some cases.

However, your question is a common reaction upon first learning about one of Fortran's gotchas: if you initialise an internal variable in its declaration then it automatically acquires the SAVE attribute. You have done exactly that in your subroutines. This is standard-conforming. If you don't want this to happen don't initialise in the declaration.

This is the cause of much surprise and complaint from (some) newcomers to the language. But no matter how hard they complain it's not going to change so you just have to (a) know about it and (b) program in awareness of it.

like image 108
High Performance Mark Avatar answered Oct 12 '22 15:10

High Performance Mark


This isn't too different from static function-scoped variables in C or C++.

Programming language design was in its infancy, back when FORTRAN was developed. If it were being designed from scratch today, no doubt many of the design decisions would have been different.

Originally, FORTRAN didn't even support recursion, there was no dynamic memory allocation, programs played all sorts of type-punning games with COMMON blocks and EQUIVALENCE statements, procedures could have multiple entry points....so the memory model was basically for the compiler/linker to lay out everything, even local variables and numeric literal constants, into fixed storage locations, rather than on the stack. If you wanted, you could even write code that changed the value of "2" to "42"!

By now, there is an awful lot of legacy FORTRAN code out there, and compiler writers go to great lengths to preserve backward-compatible semantics. I can't quote chapter and verse from the standard that mandates the behavior you've noted, nor its rationale, but it seems reasonable that backward compatibility trumped modern language design sensibilities, in this instance.

like image 40
Jim Lewis Avatar answered Oct 12 '22 14:10

Jim Lewis