Suppose I have a subroutine which accepts two arrays as input. One is given intent(in) and the other is given intent(out). The latter is derived from the former in an arbitrary manner. However, what if I pass through the same actual argument for both dummy arguments? In general, the result will not be what was intended by the subroutine. See code snippet below.
The problem is, the compiler doesn't seem to care, even though I've given intent flags. I'm using Intel Visual Fortran Composer 12, with all diagnostics. Is there a better way of coding the subroutine, or some compiler option I'm missing, to make the code safer?
module foo
contains
subroutine sub_a()
implicit none
real::array(10,10)
call sub_b(array,array)
end subroutine
subroutine sub_b(array1,array2)
implicit none
real,intent(in)::array1(10,10)
real,intent(out)::array2(10,10)
!array2 is derived from array1 somehow
end subroutine
end module foo
This is called aliasing -- referring to the same item by two different names. In most cases this is not allowed in Fortran. Your example is not legal Fortran -- see http://software.intel.com/en-us/blogs/2009/07/10/doctor-fortran-in-ive-come-here-for-an-argument-side-2/, which has this specific case, of aliasing via the same actual argument used for two dummy arguments. Fortran compilers are not required to diagnose all violations of the rules of the language and this appears to be an example that the compiler is not recognizing.
Edit: aliasing is permitted. What is forbidden is changing the value of the dummy argument through the alias, here the other dummy argument. The rules are less restrictive for pointer and target arguments. The specific rules are described in "The Fortran 2003 Handbook" by Adams et al.
Putting parentheses around the argument that is intent(in) makes the code legal since you are effectively passing a copy:
call sub_b((array),array)
Related
I'm working with an older Fortran code using subroutine calls like this:
call sub(A,,C)
With the corresponding subroutine of the form:
subroutine sub(A,B,C)
So in practice the argument B is optionally omitted here.
However, I am now creating explicit interfaces via the compiler options /warn:interface /gen-interface. I do this to debug interface errors in the code. This results in the following error (from Intel Visual Fortran compiler 19.1.0057.16):
error #8127: A null argument is not permitted when calling a Fortran routine which has an explicit interface defined. [sub]
I could make the argument B optional and move it to the end of the argument list. This would involve updating a lot of function calls. Also, I am not sure if it works in general, as e.g. several arguments may be omitted in this way in different combinations for different function calls.
What is the correct way to modernise the above code to work correctly with explicit interfaces?
Edit: The use of two consecutive commas (,,) is also a deprecated (?) language feature denoting a null data item. From the Oracle Fortran 77 language reference:
A null data item is denoted by two consecutive commas, and it means the corresponding array element or complex variable value is not to be changed. Null data item can be used with array elements or complex variables only. One null data item represents an entire complex constant; you cannot use it for either part of a complex constant.
In the comments below it was noted that this relates to the data input process, and does not apply to my problem.
The Compaq Fortran for OpenVMS manual (Compaq Fortran is a predecesor of Intel Fortran, but OpenVMS is a different operating system) has this:
If you do not want to specify a value for a required parameter, you
can pass a null argument by inserting a comma (,) as a placeholder in
the argument list. If the routine requires any passing mechanism other
than the default, you must specify the passing mechanism in the CALL
statement or the function call.
My understanding is that this feature would most likely be useful when calling procedures created in other programming languages. For example various system calls or other calls to procedures written in C. Such are also the examples offered by the Compaq Fortran manual. You can also see it in the VSI Fortran for OpenVMS manual.
The Oracle Fortran manual calls this a Fortran 77 feature accessible with a -f77 flag:
Allow null actual arguments. For example: CALL FOO(I,,,J) has two null
arguments between the first I and the final J argument.
But this is not and never has been legal Fortran. Under the hood a null pointer is passed instead if the address of an actual argument.
The way to modernize it is to go to Fortran 90 and later and use optional arguments.
subroutine sub(A,B,C)
...
real, optional :: B
In Fortran 2018 this can also be used for procedures written in other programming languages thanks to the Fortran-C interoperability and bind(C). One defines it appropriately in the interface block for such a procedure.
The call with an actual argument with B not present looks like:
call SUB(A_actual,C=C_actual)
These are the named ("keyword") arguments, also introduced in Fortran 90. You can also use them when all actual arguments are present.
E.g., Fortran 90 function with no arguments? How does FORTRAN interact with optional arguments?
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
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.
Good practice dictates that subroutine arguments in Fortran should each have a specified intent (i.e. intent(in), intent(out) or intent(inout) as described this question):
subroutine bar (a, b)
real, intent(in) :: a
real, intent(inout) :: b
b = b + a
...
However, not specifying an intent is valid Fortran:
subroutine bar (a, b)
real, intent(in) :: a
real :: b
b = b + a
...
Are there any real differences beyond compile time checking for an argument specified as intent(inout) and an argument without a specified intent? Is there anything I should worry about if I'm retrofitting intents to older, intent free, code?
According to The Fortran 2003 Handbook by Adams, et al., there is one difference between an intent(inout) argument and argument without specified intent. The actual argument (i.e., in the caller) in the intent(inout) case must always be definable. If the intent is not specified, the argument must be definable if execution of the subroutine attempts to define the dummy argument. definable means setting the value: dummy_arg = 2.0. Clearly the actual argument should be a variable if this is done. For intent(inout) the actual argument must be definable whether or not the subroutine does this. Without no intent specified, it depends on what happens on that particular invocation of the subroutine -- if the subroutine doesn't define the variable, it is OK; if it does, than there is a problem -- cases such as writing to an actual argument that is a constant will obviously cause problems.
This doesn't mean that the compiler will diagnose all of these cases -- what the standard requires a compiler to diagnose is a different issue. It would be close to impossible to detect all errors of the intent-not-specified case requirement at compile time, since violations depend on the run-time flow of the code. It is much easier for the compiler to diagnose the intent(inout) case and warn you of problems with the code.
Your question prompts me to wonder (lots to do right now) whether you might encounter a difference in behaviour if your code passes a PARAMETER as an actual argument which your sub-program then attempts to write to. Without an INTENT declaration the compiler might let this go, leading to odd behaviour. With the declaration I'd expect a compile-time error.
You and I might think that there is no difference between INOUT and no INTENT declaration, but don't forget that there are a lot of old Fortran programs out there and that compatibility with older language versions is an important feature of new standards. If it was correct (but dodgy) FORTRAN77 then a lot of people expect their code to remain correct (still dodgy) with a Fortran 90+ compiler.
A quick read of the 2003 standard does indicate that there is a difference between INOUT and no INTENT, but more close reading is required. If you do test this let us know your conclusions; if I have time later I will test it myself and let you know.
To understand the role of intent in/out, you need to know that internally, Fortran effectively passes variables by reference. This isn't always the same as actually passing by reference.
If you pass an internal subsection of an 2-D array to a subroutine, ie: data(i1:i2, j1:j2), then Fortran copies that data into a contiguous section of memory, and passes the new address to the routine. Upon returning, the data is copied back into its original location.
By specifying INTENT, the compiler can know to skip one of the copying operations.
It not only acts as a failsafe for modifying data that you want to remain unchanged, but also can speed up your code when dealing with large datasets.
To somehow expand M.S.B.'s answer, omitting intent gives you more flexibility, at the cost of less compile-time checking. Without intent, you can pass a literal constant if you know the code branch will not attempt to modify it, with intent(inout) the compiler will probably bark at you if you try it. This may be useful with "dual" procedures that will modify or not some argument depending on the options, for example:
subroutine copy(x,a,readwrite)
integer :: x, a
integer, intent(in) :: readwrite
if (readwrite == 0) then
x = a
else
a = x
end if
end subroutine
If you want to add intent to x and a, it must be inout for both, because both are potentially read and modified. But that will not allow you to write e.g.
call copy(x,3,0) ! equiv. to x=3
call copy(42,a,1) ! equiv. to a=42
This example is quite silly, but think of a more elaborate subroutine that can read from or write to a file with some complex formatting. (I'm not saying that's the best solution, but it's something you can easily find.)