This question already has answers here:
Does Fortran preserve the value of internal variables through function and subroutine calls?
(3 answers)
Fortran assignment on declaration and SAVE attribute gotcha
(2 answers)
Why is there an implied SAVE attribute in Fortran? [duplicate]
(1 answer)
Are local variables in Fortran 77 static or stack dynamic?
(2 answers)
Closed 2 years ago.
Is there a difference between initialization with declaration versus simple initialization?
For example
recursive function foo(x) result (f)
real :: x, y = 0
real :: f
...
end function
!versus
recursive function foo(x) result (f)
real :: x, y
real :: f
y = 0
...
end function
There is an important difference!
The following code implicitly sets the save attribute for variable y.
This implies that it will only be set to 0 in the first call to the function and it retains its value from the previous call for the next call.
recursive function foo(x) result (f)
real :: x, y = 0
real :: f
...
end function
In comparison the other code sets y to 0 in each call.
recursive function foo(x) result (f)
real :: x, y
real :: f
y = 0
...
end function
Related
I am trying to the assign value to a variable at the time of declaration and use that variable to declare the dimensions of some arrays as follows,
type (typ_A), intent (in) :: str_A
integer, parameter ::
x val_4 = (str_A%val_1 + str_A%val_2),
x val_5 = str_A%val_3
integer :: array_1(str_A%val_1, str_A%val_2), array_2(val_4, val_5)
In this code, the array_1 is declared properly with the expected sizes but the array_2 is not declared. Also, I am getting errors like "This symbol must be a defined parameter, an enumerator, or an argument of an inquiry function that evaluates to a compile-time constant."
Note - I can straight away use the expression of val_4 to declare array_2, but sometimes, the expression (str_A%val_1 + str_A%val_2 + ....) is very large and have to use it to define multiple arrays. Hence, for better readability and less number of lines, I want to put it in a variable (val_4 in this case)
A Fortran parameter must be computable at compile time, as the error message hints, and str_A%val_1 etc are not known at compile time.
You can't use a variable directly for this, but you can create a nested argument:
subroutine x (str_A)
type(whatever),intent(in)::str_A
call x_2 (str_A, str_A%val_1 + str_A%val_2)
contains
subroutine x_2 (str_A, mydim)
type(whatever),intent(in)::str_A
integer::mydim
integer:: ary1(mydim), ary2(mydim), ary3(mydim)
...
end subroutine x_2
end subroutine x
or if you can put at least the type and a helper function in a containing module you can do:
module t
type whatever ...
contains
pure function mydim(str_A)
integer::mydim
type(whatever),intent(in)::str_A
mydim = str_A%val_1 + str_A%val_2
end function mydim
subroutine y (str_A)
type(whatever),intent(in)::str_A
integer:: ary1(mydim(str_A)), ary2(mydim(str_A)), ary3(mydim(str_A))
...
end subroutine y
end module t
Added since you may not have considered/realized it:
Alternatively you could simply use ALLOCATABLE arrays instead; those can be allocated (not declared) with bounds computed by any runtime expression, including a local variable.
The answer of #dave_thompson_085 already answers the root for your problem.
A Fortran parameter must be computable at compile time
There are four possibilities to achieve the behaviour you want:
If you use the block statement you create a local, nested scope where you can declare new variables. You can then declare arrays that use runtime variables outside of the block for their shapes.
integer :: n
n = compute_at_runtime()
block
integer :: M(n)
! do something with M
end block
! M does not exist anymore
As #dave_thompson_085 also put it in his answer, you can use contained procedures with a local nested scope, to declare array with runtime variables that exist outside of the procedure.
Or you use allocatable for dynamic memory and automatic destruction/deallocation.
Or you use pointer for dynamic memory, but then you have to manually cleanup.
Is there a way in OCaml for a variable inside a function to keep its value between function calls? It should work like Pythons default argument, which is a reference to the same object in every function call or the function should rather yield and not explicitly return a value. The effect should be the following (if the function was to return natural numbers):
foo ();;
0
foo ();;
1
Yes this is possible. You need to define a local ref outside of the closure and access its value and modify it every time the closure is used like so:
let foo =
(* local variable x *)
let x = ref 0 in
(* the closure that will be named foo *)
fun () -> let r = !x in
x := r+1; r
In Fortran, there are two standard ways to return a result from a function. The first one is by assigning the return value of the function to the function name.
function foo()
integer :: foo
foo = 10
end function foo
The second form, standardized in Fortran 90 is through a "result" variable.
function foo result(res)
integer :: res
res = 10
end function foo
Calling either form of the function returns the value 10. My question is, what was the rationale of the Fortran 90 committee for introducing result variables? Were they standardizing a common practice? Or were they allowing programs to be more modular by not tying the function name to a function result. For example, in the second version of foo(), the name of the function foo() could be changed to bar() and the function would still work as expected when called.
However, I may be wrong. Does anyone know what the actual rationale was for introducing result variables?
Introduced at the same time as the result was recursion. Before we get to how a recursive function comes about, some clarification on what a result variable is.
The function result is always returned through a result variable, whether result is used or not.1 With result the result variable has the name specified, and without it the result variable has the same name as the function. In this latter case use of the name is a reference to the result variable and not the function.
So, if the function foo has result variable foo then we can't do direct recursion:
recursive function foo(n)
foo = foo(n-1) ! Oh dear
end function
result comes about so that we can have
recursive function foo(n) result(res)
res = foo(n-1) ! Yay
end function
[1] Well, this is true up until Fortran 2008, when the definition of variable changed. For modern Fortran use instead the term function result.
Consider the following FORTRAN program:
program functiontest
implicit none
real :: x, square
print *, "Enter a number to square"
read (*,*) x
print *, square(x)
end program functiontest
real function square(x)
real :: x
square = x * x
end function square
Why do I need to declare square to be real inside program functiontest? Haven't I already declared it a real function in its definition?
Why did the authors of FORTRAN make this design decision?
No, actually in your example you haven't declared it a real function inside the program, but it's an external function to the program. If you defined your function inside the program, as follows, or put it in a module and used it, you wouldn't have to specify it's a real function twice.
program functiontest
implicit none
real :: x
print *, "Enter a number to square"
read (*,*) x
print *, square(x)
contains
real function square(x)
real :: x
square = x * x
end function square
end program functiontest
As for why it also works the way you wrote it, it is for backwards compatibility with Fortran 77.
Put the function in a module and use the module, as shown below. Then you don't need to declare the function in the main program.
module foo
contains
real function square(x)
real :: x
square = x * x
end function square
end module foo
program functiontest
use foo
implicit none
real :: x
print *, "Enter a number to square"
read (*,*) x
print *, square(x)
end program functiontest
The square inside the function is a variable, and is not the function name. Since it is a variable, it must be declared with the right type.
I think you need to declare the type in functionlist because "in general" compiler doesn't know the type of "square". Consider a case that you have function "square" defined in a separate file, i.e. "square.f", and functionlist in another file "functionlist.f". In that case you need to compile each of those files separately and create two object file, i.e. square.o and functionlist.o. In this scenario, compiler has no clue about the "square" type, when compiling for "functionlist.o", unless you explicitly define it.
So you might ask why compiler needs to know the type of square in the first place. The answer, I think, is related to memory allocation, casting the type (e.g. when you are assigning the results to a real*8), ....
Note that, this is also common in C. There, you either need to define the prototype (in foo.h), in which the type of square is declared, or place all the functions in a file such that compiler "sees" square first.
Suppose that I want to pass a function to another function via f1(f2(k, g, x), other, junk) (f1 is defined as f1(func, other, junk) and it involves expressions like func(other).) Further suppose that both of these functions are contained in a third function f3(k, g). By calling f3(k, g) with some values of k and g, f2 isn't really a function of three variables anymore, is it? It's only a function of x since k and g are now constants. So what I want to know is whether or not there's somehow a way of saying "look, f2, you didn't know what k and g were when I defined you, but now you do since I told f3 what they were, so you can just consider yourself as a function of x, so when I pass you to f1, it sees and uses a function of only one variable."
What I think you are looking for is sometimes called a "functor/function object" or lambda expression - the ability to wrap a procedure with a number of arguments up in a way that it can be called with fewer arguments (the missing arguments being specified via other means).
In Fortran 77 this was typically approximated by passing the "missing" arguments through behind the scenes in a common block. Fortran 90/95's varied that by letting you use module variables. Both these approaches have the downside that only a single instance of the wrapped procedure can be extant at the one time, though the use of modules over common blocks is a vastly superior option for other reasons.
Fortran 2003 introduces other options - using derived types and type extension. This requires changes to the code of f1 - instead of having a dummy procedure argument the function takes a polymorphic argument, the declared type of which has a binding that has the interface similar to the former argument of f1 but with a passed object. The missing arguments then become components in extensions of that declared type. This approach brings with it a vast increase in flexibility and capability, not the least of which is that multiple instances of the wrapped procedure can then be extant at any one time, at the cost of some verbosity.
Fortran 2008 introduces another option using internal procedures, with the missing arguments passed via host association from a host procedure to the internal procedure. (This approach was not available in previous standards because internal procedures were not permitted to be passed as actual procedure arguments). Multiple instances of the wrapped procedure can be extant through the use of procedure pointers.
Examples for the four different approaches attached. Note that the other and junk entities have not been declared in any of the examples of the F3 procedure, and there may be some other omissions (or what I would consider very poor programming style) for the sake of the example. Further, note that the four approaches differ greatly in terms of the flexibility and robustness of the code (likelihood that programmer error being caught, etc).
C*******************************************************************************
C FORTRAN 77
FUNCTION F1(FUNC,OTHER,JUNK)
F1=FUNC(OTHER)+JUNK
END FUNCTION F1
C
FUNCTION F2(K,G,X)
F2=K+G+X
END FUNCTION F2
C
FUNCTION F3(K,G)
COMMON /F2COM/KC,GC
KC=K
GC=G
F3=F1(F2WRAP,OTHER,JUNK)
END FUNCTION F3
C
FUNCTION F2WRAP(X)
COMMON /F2COM/KC,GC
F2WRAP=F2(KC,GC,X)
END FUNCTION F2WRAP
!*******************************************************************************
! Fortran 90/95
MODULE m1990
IMPLICIT NONE
INTEGER :: km
REAL :: gm
CONTAINS
FUNCTION F2Wrap(x)
REAL :: x
!****
! F2 unchanged from F77, though good practice would be to make
! it (and F1 and F3) module procedures.
! ensure it had an explicit interface here.
F2Wrap = F2(km,gm,x)
END FUNCTION F2Wrap
END MODULE m1990
FUNCTION F3(k,g)
USE m1990
IMPLICIT NONE
INTEGER :: k
REAL :: g, F3
!****
km = k
gm = g
! F1 unchanged from F77.
F3=F1(F2Wrap, other, junk)
END FUNCTION F3
!*******************************************************************************
! Fortran 2003
MODULE m2003
IMPLICIT NONE
TYPE Functor
CONTAINS
PROCEDURE(fun_intf), DEFERRED :: fun
END TYPE Functor
ABSTRACT INTERFACE
FUNCTION fun_intf(f,x)
IMPLICIT NONE
IMPORT :: Functor
CLASS(Functor), INTENT(IN) :: f
REAL :: x, fun_intf
END FUNCTION fun_intf
END INTERFACE
TYPE F2Functor
INTEGER :: k
REAL : g
CONTAINS
PROCEDURE :: fun => F2_wrap
END TYPE F2Functor
CONTAINS
FUNCTION F2_wrap(f,x)
CLASS(F2Functor), INTENT(IN) :: f
REAL :: F2_wrap, x
! F2 unchanged from F77
F2_wrap = F2(f%k, f%g, x)
END FUNCTION f2_wrap
! F1 modified. Now takes a polymorphic argument in-place of the
! dummy procedure - explicit interface REQUIRED.
FUNCTION F1(f, other, junk)
CLASS(Functor), INTENT(IN) :: f
REAL :: F1, other
INTEGER :: junk
F1 = f%fun(other) + junk
END FUNCTION
END MODULE m2003
! Good practice would make this a module procedure.
FUNCTION f3(k,g)
USE m2003
IMPLICIT NONE
TYPE(F2Functor) :: f
REAL F3, g
INTEGER :: k
!****
f%k = k
f%g = g
F3 = F1(f, other, junk)
END FUNCTION f3
!*******************************************************************************
! Fortran 2008 (use of procedure pointers not illustrated).
! Should be a module proc, etc...
FUNCTION F3(k,g)
REAL :: F3, g
INTEGER :: k
INTEGER :: k_host
REAL :: g_host
k_host = k
g_host = g
! F1 unchanged from F77 (though good practice is..., etc)
F3 = F1(F2Wrap, other, junk)
CONTAINS
FUNCTION F2Wrap(x)
REAL :: x, F2Wrap
! F2 unchanged from F77.
F2Wrap = F2(k_host, g_host, x)
END FUNCTION F2Wrap
END FUNCTION F3
Supposing that I am interpreting this correctly, then yes.
program func_test
integer :: a, b
a = 4
b = 3
print *,f3(a,b)
print *,f3(b,a)
contains
function f3(k,g)
integer :: k, g, x, f3
x = 2
f3 = f1(f2(k,g,x), 3, 13)
end function f3
function f2(k, g, x)
integer :: k, g, x, f2
f2 = k+g*x
end function f2
function f1(func, other, junk)
integer :: func, other, junk
f1 = func + other*junk
end function f1
end program func_test
Unless I am mistaken, f2(k,g,x) in this example will be evaluated and then sent to f1 as an integer. If you wanted f2 to be called from f1, then you would also have to pass the arguments k, g, and x from f3 to f1.