Fortran 90 intent(in) for a recursive function - fortran

Does the following code conform to the Fortran 90 standard?
integer, pointer :: pa ! global
...
recursive subroutine foo(a)
integer, target, intent(in) :: a
if (a > 10) then
return
endif
if (associated(pa)) then
pa = 123
endif
pa => a
call foo(a + 1)
! use a
end subroutine foo
Variable a is declared with intent(in), which according to the Fortran 90 standard, section 5.1.2.3:
specifies that the dummy argument must not be redefined or become undefined during the execution of the procedure
Variable a does not get redefined at the level of recursion of foo(a); instead, we save a pointer to a so we can redefine a on a lower level of recursion.
In other words:
foo(a) ! do not change a, save the pointer to a
foo(a + 1) ! change a, save the pointer to a + 1
foo(a + 1 + 1) ! change a + 1, save the pointer to a + 1 + 1, and so on.
Based on my understanding of the standard, the lifetime of foo(a + 1) is a subset of the lifetime of foo(a), so a should not be changed.
Is it safe for the compiler to assume that foo() has "undefined behaviour" (or Fortran's equivalent of it)?

The answer depends on the value of the actual argument that gets associated with a that the procedure is initially called with, and the association status of pa prior to the first call.
If a is greater than 10, the code is conforming (and not very exciting).
If a is equal to 10, and the pointer association status of pa is undefined, the code is non-conforming. The associated intrinsic requires its actual argument to be defined. If a is equal to 10 and the pointer association status of pa is not undefined, the code is conforming.
If a is less than 10, the code is non-conforming. The INTENT(IN) dummy argument a of the first instance of execution of the procedure is redefined via assignment to the pointer pa during nested execution of the next instance. The rules around INTENT(IN) require that the value of non-pointer dummy arguments not be changed during invocation or execution of the procedure, directly or indirectly.
Beyond diagnostics not relevant here, a conforming Fortran processor can do whatever it wants when executing unconforming code, but conformance versus non-conformance here is an execution time question.
Many corrections to the Fortran 90 standard have been effectively issued over the years, perhaps most of which have been made via edits to subsequent standards. Words in later standards are slightly different, but requirements in this area haven't changed.

Related

Can a Fortran function return multiple variables?

In the example function below how can one tell whether a, b or c are input or output values, other than from the context?
Also, if example() is called is a value assigned to c outside the scope of example()?
function example(a, b, c)
real*8 a, b, c
c = a + b
example = c
end function example
Fortran has the possibility to specify intent attribute:
The INTENT attribute specifies the intended use of a dummy argument. An INTENT (IN) dummy argument is suitable for receiving data from the invoking scoping unit, an INTENT (OUT) dummy argument is suitable for returning data to the invoking scoping unit, and an INTENT (INOUT) dummy argument is suitable for use both to receive data from and to return data to the invoking scoping unit.
Furthermore one can specify a result attribute or give the function a type,
So one could write:
double precision function example(a, b, c)
implicit none
double precision, intent(in) :: a, b
double precision, intent(out) :: c
c = a + b
example = c
end function example
or
function example(a, b, c) result(res)
implicit none
double precision, intent(in) :: a, b
double precision, intent(out) :: c
double precision :: res
c = a + b
res = c
end function example
Note: I also added the "implicit none" and replaced the real*8 by double precision.
You have an answer which talks about intents for arguments. These provide valuable hints to the programmer (as a form of documentation) and compiler as to how the arguments are used. These intents give an idea of the restrictions on an argument and apply to procedures (subroutines as well as functions) more widely.
However, some dummy arguments may even not be allowed to be given an intent. Further, an intent specification doesn't mean that the argument is used in that way (intent(in) arguments needn't be referenced; intent(inout) variables needn't be modified; intent(out) arguments needn't be defined).
Ultimately you will have to look at the function's behaviour.
Given the function of the question
function example(a, b, c)
real*8 a, b, c
c = a + b
example = c
end function example
we can consider a and b to be "inputs" and they must be defined when the function is entered and their values are used in evaluating the function result. The function result is called example but there is a side-effect of modifying c, an "output". Its value on entering the function isn't needed, and it needn't even be defined.
Now, this being Fortran, there is a subtlety to note. You ask
is a value assigned to c outside the scope of example?
and the answer is, possibly.
If example were a subroutine then yes, the actual argument matching c would have a value defined after the subroutine call. With example a function, then maybe not.
Consider:
implicit none
real*8 a, b, c, d
real*8 example ! Really you should be using an explicit interface
a = 1.
b = 2.
c = 0.
d = 0.
print*, example(a,b,c)
print*, c
if (.false..and.example(a,b,d)>0) print*
end program
then although the value of c is modified by this function reference, the variable d actually becomes undefined!1
1 By "undefined" I mean that it doesn't have a value that you can reliably query or use. Because Fortran allows a compiler to short-circuit the evaluation of the function but doesn't it require it, it says that the value becomes undefined. You can't rely on side effects from a function if you can't be sure that the function is used.

How do I read a parameter from a text file in a FORTRAN module? [duplicate]

In Fortran, is the PARAMETER attribute set at runtime or compilation time?
I was wondering if I can pass in the size the of the array at run time and have this set as PARAMETER.
Can this be done? If so, how? If not, why?
Yes, as repeatedly answered, a named constant (an object with the parameter attribute) must have its initial value "known at compile time". However, as you talk about the size of arrays I'll note something else.
When declaring the shape of an array there are many times when the bounds needn't be given by constant expressions (of which a simple named constant is one example). So, in the main program or a module
implicit none
...
integer, dimension(n) :: array ! Not allowed unless n is a named constant.
end program
the n must be a constant. In many other contexts, though, n need only be a specification expression.
implicit none
integer n
read(*,*) n
block
! n is valid specification expression in the block construct
integer, dimension(n) :: array1
call hello(n)
end block
contains
subroutine hello(n)
integer, intent(in) :: n ! Again, n is a specification expression.
integer, dimension(2*n) :: array2
end subroutine
end program
That is, array1 and array2 are explicit shape automatic objects. For many purposes one doesn't really need a named constant.
Beyond the array size, the following is certainly not allowed, though.
implicit none
integer n, m
read(*,*) n, m
block
! n and m are specifications expression in the block construct
integer(kind=m), dimension(n) :: array ! But the kind needs a constant expression.
...
end block
You need dynamic allocation if the size of your array is to be defined as runtime. All parameter (constants) must be defined as compiling time.
The value of a parameter is set at compile time.
A declaration such as
integer, parameter :: number_of_widgets = numwidge
requires that numwidge be known at compile time, indeed known before it is encountered on the rhs of the declaration.

Passing parameters to a subroutine in Fortran

I'm trying to understand how to pass some variables with values, to a subroutine, from another subroutine.
I have the code:
program pg
call sub()
end
subroutine sub()
character :: P(12,12)
character :: D(20), N(26), userInput
integer :: A,B
A = 5
B = 2
userInput = "hello"
call test(P,D,N,userInput,A,B)
end subroutine
subroutine test(P,D,N,userInput,A,B)
end subroutine test
But that gives me a warning of:
Warning: Type mismatch in argument 'p' at (1); passed CHARACTER(1) to REAL(4)
I'm not exactly sure on how to get rid of this warning, let alone if the subroutine call is correct (syntax wise). Any help would be much appreciated.
First, why this error is happening: You have not explicitly declared any variables in subroutine test so by default, the IMPLICIT variable type rules are applied - variables starting with [A-H,O-Z] are treated as single-precision reals (REAL(4)) and the remainder (starting with [I-N]) are integers. In this case, the real arguments to test are P, D, userInput, A, and B; N is treated as an integer. Also these are all treated as scalar quantities since no dimension information is provided in test.
In subroutine sub, the variable P is declared as a 12-by-12 array of length-1 strings (single characters or CHARACTER(1)). This explains why you're getting the type mismatch error.
Advice: Read up on the IMPLICIT statement and start your code with IMPLICIT NONE, always. This forces you to declare all your variables. This slight inconvenience allows the compiler to catch typos and namespace collisions and is considered best practice. It won't solve your next problem (P, D, and N are arrays passed in as arguments to a routine which expects them to be scalars) but it will get rid of the type mismatch error.
For bonus points, look into the INTENT attribute for argument declarations. If you know that certain arguments are read-only or will only have their values set within a routine, you can declare them as INTENT(IN) or INTENT(OUT). This is an added guard against accidentally changing read-only variables or reading variables before they've been initialized.

Is initializing a variable in between variable declarations forbidden?

I have something like
integer a
integer b
b = 0
integer c
a = 0
c = 0
which does not work with the error
"A specification statement cannot appear in the executable section."
However, changing it to
integer a
integer b
integer c
a = 0
b = 0
c = 0
works.
Yes, this is forbidden in Fortran. This is defined in the Fortran 2008 Standard, Cl. 2.3.2 "Statement order":
1 The syntax rules of clause 2.1 specify the statement order within program units and subprograms. These rules
are illustrated in Table 2.1 [...]. Table 2.1 shows the ordering rules for statements and applies to
all program units, subprograms, and interface bodies. Vertical lines delineate varieties of statements that may
be interspersed and horizontal lines delineate varieties of statements that shall not be interspersed. [...] Between USE and CONTAINS statements in a
subprogram, nonexecutable statements generally precede executable statements [...]
(Emphasis mine)
[Slightly off-topic, but related] Please note that while
integer :: a
integer :: b = 0
integer :: c
is allowed, this has the side effect that b gets the save attribute. That is typically not what you want...
The error message is quite clear. Fortran programs and subprograms are divided into two parts. First the specification part where you use modules, define variables, derived types, interfaces... And then the executable part where you put the actual executable statements or control structures.
It is not possible to mix them.
The situation is murkier in f2008, with the BLOCK construct. That construct necessarily lies among the executable statements, but is often there for the sole purpose of adding the capability to place some specification statements after executable statements, as when an assumed length pointer is to be pointed at anonymous memory.
EDIT: Example
module anonymous
use ISO_C_BINDING
implicit none
interface
function malloc(size) bind(C,name='malloc')
import
implicit none
type(C_PTR) malloc
integer(C_SIZE_T), value :: size
end function malloc
subroutine free(ptr) bind(C,name='free')
import
implicit none
type(C_PTR), value :: ptr
end subroutine free
function strlen(str) bind(C,name='strlen')
import
implicit none
type(C_PTR), value :: str
integer(C_SIZE_T) strlen
end function strlen
end interface
contains
function hello()
type(C_PTR) hello
character(LEN=*,KIND=C_CHAR), parameter :: world = &
'Hello, world'//C_NULL_CHAR
character(LEN=len(world),KIND=kind(world)), pointer :: fptr
hello = malloc(len(world,KIND=C_SIZE_T))
call C_F_POINTER(hello,fptr)
fptr = world
end function hello
end module anonymous
program test
use anonymous
implicit none
type(C_PTR) cptr
character(LEN=:,KIND=C_CHAR), pointer :: fptr
integer(C_SIZE_T) hello_len
cptr = hello()
hello_len = strlen(cptr)
BLOCK
character(LEN=hello_len,KIND=C_CHAR), pointer :: temp
call C_F_POINTER(cptr,temp)
fptr => temp
end BLOCK
write(*,'(*(g0))') fptr(1:strlen(cptr))
end program test

No lifting of scalar arguments to arrays in Fortran

Why is it that Fortran will promote a scalar expression to an array, in an expression, but not as an argument to a procedure? In particular, why did the standards body make this design decision? Is it solely because of ambiguity, should the procedure be overloaded? Could an error message in that situation be an alternative approach?
For example, In the code below, the last statement, x = foo(7), produces the GFortran error: Error: Rank mismatch in argument 'a' at (1) (1 and 0).
module m
public :: foo
contains
function foo(a) result(b)
integer, dimension(:) :: a
integer, dimension(size(a)) :: b
b = a+1
end function foo
end module m
program p
use m
integer, dimension(4) :: x
integer, parameter, dimension(4) :: y = (/1,2,3,4/)
x = 7
x = foo(x)
x = foo(y)
x = foo(x + 7)
x = foo(7)
end program p
This question should have asked about why an array assignment will promote a scalar value source to an array target; unlike an array function. I expect that's simply a convenient special case though. Any comments gratefully received in the begging caps below.
If you want the function to handle scaler and array arguments, declare it as "elemental" and with scaler dummy arguments. Then it will be able to handle both scaler and array actual arguments, including scaler expressions. Will that meet your need?
The change:
elemental function foo(a) result(b)
integer, intent (in) :: a
integer :: b
b = a+1
end function foo
Perhaps they provided a way to do what you want, and one way was enough?
Procedure calling in Fortran with explicit interfaces (which you get automatically when using module procedures) requires a TKR (type, kind, rank) match. As an array is a different type than a scalar, not to mention the rank mismatch, this is not allowed.
Is it because of ambiguity should the procedure be overloaded?
That would be a problem, yes.
Could an error message in that situation be an alternative approach?
Could pink unicorns exist? Maybe, but to the best of my knowledge they don't. IOW, the Fortran standard currently requires TKR matching, and thus a standard conforming compiler must enforce this requirement. If you want to change that, I recommend making a proposal to the standards committee.
I would think the answer to this is pretty clear. Let's slightly modify your example:
module m
public :: foo
contains
function foo(a) result(b)
integer, dimension(:) :: a
integer, dimension(size(a)) :: b
b = a+1
a(2) = -777 ! new line; modify one element
end function foo
end module m
program p
use m
integer :: x
integer, dimension(4) :: y
x = 7
y = foo(x) ! pass a scalar
end program p
what is x supposed to be after the call to foo?
Now, sure, you could have the semantics of argument passing change depending on whether or not it's an intent(in) variable, but that is not something which is going to clarify things for programmers.
If the function call is supposed to 'distribute' somehow over array elements, then as MSB points out, elemental is the way to go. Otherwise, one just makes sure one's arguments match one's parameters.