Am working with some legacy FORTRAN code. The author defined a function (not a subroutine, but a function -- that's going to be important) called REDUCE_VEC(). It accepts a 1D array and returns a scalar real*8. So, if you want to "reduce" your vector, you make a call to the function
RV = REDUCE_VEC(V1)
and everything is fine. But occasionally, he has lines that look like
CALL REDUCE_VEC(V2)
So, two questions: 1) What the heck would this second form of the call do? (Note that there is no way to return data.) 2) This won't even compile under gfortran, even though it did with PGI, so is this even legal FORTRAN?
Thanks.
This will compile with many processors if the interface is implicit, because the compiler cannot check that, it just calls some symbol. Consider the following:
function f(a)
dimension a(*)
f = 0
do i=1,10
f = f + a(i)
end do
end function
program p
call f([1.,2.,3.,4.,5.,6.,7.,8.,9.,10.])
end program
Compiles and does not even crash immediately with ifort, whereas sunf90 and gfortran will compile that only if it is in separate source files and then the result also does not crash on my machine. If the return value is placed in register, it may cause no harm to the rest of the program, but a stack corruption is quite likely otherwise.
It is not legal Fortran. As presented it is more than likely a programming error (it is possible for the same name in different scopes to refer to different things, but that's not what is implied by the question). If the Fortran processor happens to support an extension to the language that allows this, then what happens is up to the Fortran processor. Otherwise, "anything" could happen, where "anything" could include (but is not limited to) "nothing", or "very, very bad things".
Related
The Code
The following MWE describes what I want to use (note that I did not design this, I am merely trying to use someones code, I would not usually use global variables).
PROGRAM MAIN
IMPLICIT NONE
integer :: N
real(8), allocatable :: a(:,:)
N=3
allocate(a(N,3))
a=initialize_array()
CONTAINS
function initialize_array() result(a)
IMPLICIT NONE
real(8) :: a(N,3)
a=1
end function initialize_array
END PROGRAM MAIN
The Problem
gfortran gives an error which reads Error: Variable 'n' cannot appear in the expression at (1), pointing to to the real(8) :: a(N,3) inside the function.
In a subroutine it would work, so what might be the problem here?
The question
Why does ifort (v. 15.0.3) compile this, while gfortran (v. 4.8.4) does not?
As has been commented by others, it is hard to say whether something is clearly allowed: the language is mostly based on rules and constraints giving restrictions.
So, I won't prove that the code is not erroneous (and that gfortran is not allowed to reject it), but let's look at what's going on.
First, I'll object to one thing given by High Performance Mark as this is slightly relevant:
The declaration of an array with a dimension dependent on the value of a variable, such as a(N,3), requires that the value of the variable be known (or at least knowable) at compile time.
The bounds of an explicit shape array need not always be given by constant expressions (what we loosely define as "known/knowable at compile time"): in some circumstances an explicit shape array can have bounds given by variables. These are known as automatic objects (and the bounds given by specification expressions).
A function result is one such place where an automatic object is allowed. In the question's example for the declaration of the function result, N is host associated and forms a specification expression.
Rather than exhausting all other constraints to see that the declaration of a truly is allowed, let's look at how gfortran responds to small modifications of the program.
First, a trimmed down version of the question's code to which gfortran objects.
integer n
contains
function f() result(g)
real g(n)
end function f
end program
The function result for f has the name g. It doesn't matter what we call the function result, so what happens when we call it f?
integer n
contains
function f()
real f(n)
end function f
end program
This compiles happily for me.
What if we frame this first lump in a module instead of a main program?
module mod
integer n
contains
function f() result(g)
real g(n)
end function f
end module
That also compiles.
The natural conclusion: even if gfortran is correct (we've missed some well-hidden constraint) to reject the first code it's either horribly inconsistent in not rejecting the others, or the constraint is really quite strange.
I think this might be an explanation, though like #VladimirF I can't actually either recall or find the relevant section (if there is one) of the standard.
This line
real(8) :: a(N,3)
declares that the result of the function is an array called a. This masks the possibility of the same name referring to the array a by host association. The a inside the function scope is not the a in the program scope.
The declaration of an array with a dimension dependent on the value of a variable, such as a(N,3), requires that the value of the variable be known (or at least knowable) at compile time. In this case giving n in the host scope the attribute parameter fixes the problem. Though it doesn't fix the poor design -- but OP's hands seem tied on that point.
It doesn't surprise me that the Intel compiler compiles this, it compiles all sorts of oddities that its ancestors have compiled over the years for the sake of backwards compatibility.
I only offer this half-baked explanation because experience has taught me that as soon as I do one of the real Fortran experts (IanH, francescalus, (usually) VladimirF) will get so outraged as to post a correction and we'll all learn something.
When dealing with optional arguments in fortran I believe it's typical to branch using the present() intrinsic, i.e.:
subroutine foo(ii,jj)
implicit none
integer, intent(in) :: ii
integer, optional :: jj
if (present(jj)) then
! do something
else
! do something else
end if
end subroutine foo
My assumption (coming from a C++ world) is that present() is hopefully a compile-time construct, and that there won't be any associated runtime performance penalty. I expect that the compiler should be able to (should be required to?) optimise the if statement shown above away, depending on whether foo(ii) or foo(ii,jj) is called.
How is the present() intrinsic handled by compilers in practice? Does the fortran spec guarantee certain behaviour?
PRESENT is a runtime concept - to the extent that the presence of an argument may depend on aspects of the program that cannot be determined until runtime (based on input read from a file or similar).
The implementation of the equivalent of PRESENT in a C++ program would similarly be a runtime concept. Note that C++'s defaulted arguments feature is not quite the same concept as Fortran's optional arguments feature (though it could be part of an equivalent implementation).
Beyond compiler optimization cleverness, if you want compile time resolution of things similar to C++'s defaulted arguments or function overloading, then consider using multiple specific procedures behind a generic name, one variant of the specific with the "optional" argument, the other without.
That depends (what else did you expect? :-)
If you use gfortran with a recent version, and do a lot of work in at least one of the branches, and use LTO or put everything into one file, the compiler will clone the function for you (via constant propagation). Otherwise, probably not. If you want to find out if the procedure foo has been cloned, grep for foo.*constprop in the assembly file.
An alternative to one subroutine with an optional argument is two subroutines, one with the argument, and one without, sharing the same interface. I don't think there is a run-time cost for doing this as opposed to giving the two versions of the subroutine different names. Schematically, it looks like this:
interface foo
module procedure foo_1,foo_2
end interface foo
contains
subroutine foo_1(ii)
! some code
subroutine foo_2(ii,jj)
! some code
I am a newbie to Fortran. Please look at the code below:
c main program
call foo(2)
print*, 2
stop
end
subroutine foo(x)
x = x + 1
return
end
In some implementations of Fortran IV, the above code would print a 3. Why is that? Can you suggest an explanation?
How do you suppose more recent Fortran implementations get around the problem?
Help is very much appreciated. Thank You.
The program breaks the language rules - the dummy argument x in the subroutine is modified via the line x = x + 1, but it is associated with something that is an expression (a simple constant). In general, values that result from expressions cannot be modified.
That specific code is still syntactically valid Fortran 2008. It remains a programming error in Fortran 2008 - as it was in Fortran IV/66. This isn't something that compilers are required to diagnose. Some may, perhaps with additional debugging options, and perhaps not till runtime.
Because the program breaks the language rules anything could happen when you run the program. Exactly what depends on the code generated by the compiler. Compilers may have set aside modifiable storage for the value that results from the expression such that it internally looks like a variable (the program might print three and the program carries on), that modifiable storage might be shared across the program for other instances of the constant 2 (suddenly the value of 2 becomes three everywhere!), the storage for the value of the constant might in non-modifiable memory (the program may crash), the compiler may issue an error message, the program may get upset and sulk in its bedroom, the program might declare war on a neighbouring nation - it is a programming error - what happens is unspecified.
As of Fortran 90, facilities were introduced into the language to allow programmers to write new code that is practical for compilers to check for errors such as these (and in some cases compilers are required to check for errors if they are to be regarded as standard conforming).
For the code as presented, the main program and the subroutine are to be regarded as separately compiled - the main program is unaware of the details of the subroutine and vice versa (it is possible that the subroutine could be compiled long after the main program, on a different machine, with the outputs of the two being linked together at some later stage - without fancy link time behaviour or static analysis it is therefore not possible to resolve errors such as this). Language rules are such that when compiling the main program the compiler must implicitly assume the details of the interface of the subroutine based only on the way the subroutine is referenced - inside the main program the subroutine has an implicit interface.
Fortran 90 introduced the concept of an explicit interface, where the compiler is explicitly told what the interface of the subroutine in various ways, and can then check that any reference to the subroutine is consistent with that interface. If a procedure is a module procedure, internal procedure or intrinsic procedure - that interface is automatically realized, alternatively for external subprograms, procedure pointers, etc, the programmer can explicitly describe the interface using an interface block.
In addition, Fortran 90 introduced the intent attribute - a characteristic of a dummy argument of a procedure that is also then a characteristic of the interface for a procedure. The intent of the argument indicates to the compiler whether the procedure may define the argument (it also may implications for default initialization and component allocation status) and hence whether an expression could be a valid actual argument. x in subroutine foo would typically be declared INTENT(INOUT).
Collectively these new language features provide a robust defence against this sort of programming error when using compilers with a basic level of implementation quality. If you are starting with the language then it is recommended that these new features become part of your standard approach - i.e. use implicit none, all procedures should generally be module procedures or internal procedures, use external procedures only when absolutely required, always specify dummy argument intent, use free form source.
Consider:
program main
real, allocatable, dimension(:) :: foo
integer n
n=10
call dofoo(foo,n,1)
allocate(foo(n))
call dofoo(foo,n,0)
end program main
subroutine dofoo(foo,n,mode)
real foo(n)
integer i,n,mode
if(mode.eq.1)then
n=6
return
endif
do i=1,n
foo(i)=i
enddo
return
end subroutine dofoo
Is there anything wrong with the above code? (It works with gfortran) I pass in an un-allocated array the first time, but I don't touch it -- Is there anything in the standard that could cause this to behave in a system dependent way?
You've almost answered your own question. Yes, by the standard, it is always illegal to pass an unallocated allocatable arrays as an actual argument if you don't have an interface in scope.
If you have an interface in scope it is only legal if the dummy argument is also allocatable.
And yes I've been bitten by it. My work around has been to allocate to zero size before the call.
The answer by Ian Bush correctly states that the use in the question is not allowed. We can be more precise, though. (References in parentheses to the Fortran 2018 standard.)
There are three cases where an unallocated allocatable actual argument may be used:
when the dummy argument is also allocatable (only since Fortran 2003, or Fortran 95+TR-15581) (15.5.2.6 p.2)
when the dummy argument is an optional ordinary argument (only since Fortran 2008) (15.5.2.12 p.1, 15.5.2.4 p.7)
when the procedure is an intrinsic inquiry function (15.5.2.4 p.7, 16.1 p.2)
There is no exception for "unused" dummy arguments. These restrictions apply whether the allocatable argument is an array or a scalar.
Any other use means that the program is non-conforming (15.5.2.4 p.7, 15.5.2.7 p.2).
In a conforming program, each of these acceptable cases has an explicit interface available. An allocatable or optional dummy argument requires one (15.4.2.2 p.1(3)) and an accessible intrinsic procedure always has an explicit interface available (15.4.2.1 p.1).
These requirements on the program are not ones a compiler is required to be able to analyse. Such a non-conforming program doesn't necessarily mean that you will see problems when compiling and running. In the case of the program of the question, which doesn't attempt to dereference in a bad way, you may well get away with it. However, it's not good to write non-conforming programs and very bad to rely on them "working".
There are some ways where things may go wrong:
run-time checks
compile-time checks
the dummy having the value attribute (again, explicit interface required in this case)
That is, your program could behave differently with some compilers/compiler options. Your compiler may refuse to compile the program if it notices that you should have an explicit interface available. The program may abort when entering the subroutine if the runtime checks whether the argument is allocated. The runtime may do something very unexpected if trying to make an anonymous definable copy of the array with the value attribute when the actual argument isn't allocated.
For the question there's another non-compliance to worry about. The explicit-length dummy argument foo(n) means that the actual argument must have at least n elements. An unallocated array doesn't have at least n elements (for any, even zero, n). If foo was intent(out) a compiler would be within its rights doing something to "undefine" these elements of the actual argument. This may fail.
In my Fortran code I made the following call to the dnrm2 routine:
d = dnrm2(n, ax, 1)
Just a simple call that would return me a double precision result.
The question is, should I declare the function at the start of my script? I found that if I don't declare it, when I compile the code in 32 bit Windows, then the result is correct.
But if I compile the code in 64 bit Windows, then the result isn't be correct.
Why is this so? Must an external routine always be declared in Fortran?
If you don't correctly describe your subprograms (subroutines and functions) to a calling program, the compiler may not correctly call them. Fortran compiles each unit separately, so the compiler doesn't "know", by default, about the characteristics of other subprograms. There are several ways that you can describe/declare a subprogram in Fortran 90/95/2003.
The easiest and best method is to place your subprograms into a module and then "use" that module in the calling program. This automatically makes the interface known to the compiler and will enable the compiler to check the consistency of actual arguments (in the call) and dummy arguments in the subprogram. It will also make known the return type of a function. The various subprograms in a module have their interfaces known to each other.
You can also write an "interface" containing a subprogram declaration that matches the declarations of the actual subprogram. (This method can be very similar to the style of including header files in C.) This method is more work and prone to error because you have to manually maintain consistency between the actual subprogram and interface whenever changes are made. The interface method is useful when you don't have the code to the subprogram or the subprogram is written in a language other than Fortran.
Or you can simply declare a function name to specify the type-return of the function, but this won't give you any checking of the arguments. In my opinion this method is weaker since having the compiler check argument consistency eliminates a major class of programming mistakes.
I don't do Fortran, but in C, the size of a pointer and the size of a long int varies between 32 and 64 bit OS'es, but the size of an int does not. Perhaps the program is using ints to do pointer arithmetic?