In December 2025, I initiated a thread on INTENT(…) declarations. The context was the NRL/NASA HWM14 software (Fortran 90). We established that there were some “intent(out)” declarations in the code that should be changed to “intent(in out)”. These errors still persist in the HWM14 code repositories (NRL original as well as Jacob Williams’ Github version.
Today, I made some code modifications and test runs to examine whether the code that compilers generate is affected by the presence of incorrect INTENT declarations. I started with the NRL sources, corrected as to INTENT, compiled, ran and saved the result to a file. I then removed all the INTENT declarations, then rebuilt the exe, and saved the result to a new file. Comparing the output files produced a surprising result: the output text files were byte-for-byte identical. This result was reached in three cases : (i) Gfortran 13.4 under Cygwin, (ii) Intel Fortran IFx compiler 2024.2.1 and (iii) NAG 7.2 in Windows 11.
Silverfrost FTN95 also displays the same behavior, although one has to provide different versions of unformatted data files for it than the others (the record length information conventions of FTN95 are different).
If the presence of INTENT declarations (correct or not) has no effect on the results of the computations, why bother with writing such declarations, when the effort to write such declarations and testing them for correctness is considerable? Why not stay with F77 type declarations and stop wasting time writing and debugging INTENT declarations?
In other words, can someone point out examples where having INTENT declared, and correctly so, produces some benefits or avoids harmful errors?
Thanks.
Argument intent allows for compile time checking of correctness when interfaces are provided as well (generated automatically for routines within modules). When intent is added to a variable declaration, the compiler verifies that intent(in) are not modified, that’s basically it.
Thanks for replying. You wrote about the compiler checking that a dummy argument with intent(in) is not modified. Along the same lines, does the compiler check that there is at least one statement in the subroutine in which a dummy argument with intent(out) does get defined? Is there a check that the variable has been defined before exiting the subroutine?
The thing is: after the code compiles correctly (and you’re sure your INTENTions are honored by the code), the intent attribute is not really needed by the object file. The generated .mod files will still have information about them, though.
Also, if you have a derived type that implements a final procedure, then some extra code is actually generated for intent(out).
And, as of now, most of the OOP’s SOLID is supported (we’re only missing the I), which means sometimes you’ll have to write empty procedures just to implement an abstract type —so, it’s a bad idea to make the compiler complain about empty procedures; although it usually has an option to warn about unassigned intent(out) arguments.
I’ll add that it’s alot easier for me, the reader, looking at a piece of code to know what it’s doing when the intents have been specified. Yes you could add comments documenting the intent, but comments can get out of sync with the code. This also makes it much easier when wrapping other codes as I know what I need to provide in and what’s coming out without having to read the entire code base.
No, I would not expect such an expensive test to be offered. There is no point in checking that every single element (out of maybe ten million) of an array has been defined. You can get a check that any subsequently referenced element has been defined (with nagfor’s -C=undefined, say).
You say you get exactly the same output. Not knowing how sensitive your calculations are to “processor dependencies”, that is not very surprising. In my experience, it’s not unusual for SUM, MATMUL, DOT_PRODUCT, trigonometric-functions to show slight differences, but they can be hidden by printing only few significant digits.
Adding INTENT attributes will never make a correct program into an incorrect program. But it can make an incorrect program into a program that will not compile, or one that will error-terminate before it produces wrong output. It might also make a (correct or incorrect) program normal-terminate faster.
This is a classic case of something seen elsewhere in human affairs: psychologically, we tend to be more aware of the costs of what we do (sitting here writing INTENTs) and the benefits of what we don’t do (would be nice to go sailing), than vice versa.
module mod1
implicit none
contains
subroutine s(a)
integer, intent(out) :: a
end subroutine
end module mod1
$ ifort -diag-disable=10448 -c -warn intent-out.f90
intent-out.f90(5): warning #6843: A dummy argument with an explicit INTENT(OUT) declaration is not given an explicit value. [A]
subroutine s(a)
-----------------^
intent-out.f90(5): remark #7712: This variable has not been used. [A]
subroutine s(a)
-----------------^
module m
implicit none
contains
subroutine sub(x,y1,y2,z)
real, intent(in) :: x
real, intent(out) :: y1,y2,z(2)
y1 = x
z(1) = x
end subroutine sub
end module m
program main
use m
implicit none
real :: x = 10.0, y1, y2, z(2)
call sub(x, y1, y2, z)
print*,y1,y2
print*,z
end program main
gfortran -Wall says
xintent_out.f90:4:21:
4 | subroutine sub(x,y1,y2,z)
| 1~
Warning: Dummy argument ‘y2’ at (1) was declared INTENT(OUT) but was not set [-Wunused-dummy-argument]
But isn’t it because the check is only about being in a variable definition context?
As @themos said, it would be unreasonable to expect a check for your million elements array… Or, if the variable is a derived type, expecting all the components to be touched somehow.
I think ifort can assign some unusual value at runtime for certain types, but that check is not about intent but about being used before being defined.
As a developer, looking at a subroutine, I find it very useful if the INTENT(in) is correctly set. This clearly indicate that these arguments are purely input arguments and not modified. Whether the results is INTENT(out) or INTENT(inout) does not matter that much for my understanding of the routine - it means that those variables are some kind of result. But with big complex routines, with lots of arguments, where most of them are in reality pure inputs, it is nice to know what is an input and what is a result.
See the below toy example, in which the compiler has to create a temporary array for the actual argument a(::2) upon the call of bar() (copy-in). Specifying intent(in)for the dummy argument tells the compiler that there’s no need to copy-out the content of the dummy argument to the actual argument upon exit.
Of course the compiler may or may not use this information, and it doesn’t have to. But both gfortran and ifx use it, and the binary code is different when commenting out the intent(in) :: a line. Try by yourself here: Compiler Explorer
module foo
contains
integer function bar(a,n)
integer :: a(n)
intent(in) :: a
bar = sum(a)
end function
end module
program test
use foo
integer :: a(1000), i
a =[(i,i=1,1000)]
print*, bar( a(::2), 500 )
end
Similarly with implicit none, if you have explicitly declared all your variables, then you can remove implicit none from your code and you should expect identical binaries and identical output. Its main purpose is not to change the program, but to force the programmer to write a correct program.
I would not put intent in the same category as implicit none . A program without type declarations can be mechanically translated to one with declarations, and I have such a Python script in my Fortran-to-C translator. The translator would not normalize Fortran code by adding intents, since that can change the meaning of the program. For example, intent(out) deallocates allocatable arguments.
Intent does more than just that. It also allows the compiler to verify that the actual argument matches the dummy argument. For example if the actual argument is intent(in) or is an expression, then the compiler will tell you if the dummy argument is intent(out) or intent(inout). That happens typically early at compile time, not at run time, so it saves many hours of debugging when a programmer makes that error. Along these lines, it should also be mentioned that no intent (ala pre-f90) is not the same as intent(inout).
INTENT is required for PURE/ELEMENTAL procedures and procedures used to overload operators and assignment, is it not? And I would not always want INTENT specified, as not having it specified is not the same as INTENT(INOUT); and particularly when working with older codes but occasionally even with new code I do not want INTENT specified so some procedure forms can have constants passed as arguments that require being changed in other call forms. I always specify INTENT for
type-bound procedures.
It would have been nice to have a fourth INTENT type to explicitly cover the case currently only defined by not specifying INTENT. although I cannot think of a name I like for it at the moment INTENT(IN.OR.INOUT) seems a bit verbose
The problem with not specifying it is that if I am working with a piece of existing code I cannot tell the difference between a declaration where no one has considered adding the intent or if it needs left off, so if I want the code to have intents specified I need to determine which it is and leave it blank if it needs to be, which means possibly doing the same inspection in the future (repeatedly).
So I end up putting a comment on the declaration. I would prefer an explicit INTENT type. But definitely hard to be any shorter than nothing.