subroutine print_char(this,header) character(len=*), intent (in) :: this logical, optional, intent (in) :: header ! THIS IS THE WRONG WAY if (present(header) .and. header) then print *, 'This is the header ' endif print *, this end subroutine print_char
subroutine print_char(this,header)
character(len=*), intent (in) :: this
logical, optional, intent (in) :: header
! THIS IS THE RIGHT WAY
if (present(header)) then
if (header) print *, 'This is the header '
endif
print *, this
end subroutine print_char
Explanation
The first method is not safe because the compiler is allowed to
evaluate the header argument before the present function is evaluated.
If the header argument is not in fact present an out of bounds memory
reference could occur, which could cause a failure.
program intent_gotcha type mytype integer :: x real :: y end type mytype type (mytype) :: a a%x = 1 ; a%y = 2. call assign(a) ! a%y COULD BE UNDEFINED HERE print *, a contains subroutine assign(this) type (mytype), intent (out) :: this ! THIS IS THE WRONG WAY this%x = 2 end subroutine assign
subroutine assign(this)
type (mytype), intent (out) :: this
! THIS IS THE RIGHT WAY
this%x = 2 ; this%y = 2.
end subroutine assign
end program intent_gotcha
Explanation
The problem is that when intent(out) is used with a derived type, any
component not assigned in a procedure could become undefined on exit.
For example, even though a%y was defined on entry to this routine, it
could become undefined on exit because it was never assigned within
the routine. The lesson is that all components of a derived type
should be assigned within a procedure, when intent(out) is used.
Intent(out) behaves like the result variable in a function: all components
must be assigned.
As an alternative, use intent(inout).
do i = 1, 128 write (unit=6,fmt='(a)',advance='no') 'X' end do
We expect this program to print 128 X's in a row. However, unexpected behavior may occur if the record length for unit 6 is less than 128.
One can inquire the record length in the follow way:
open(unit=6)
inquire(unit=6, recl=i)
print *, 'recl =', i
Explanation
All Fortran I/O is still record based. Non-advancing I/O allows partial reads
and writes within a record. For many compilers the default record length
is very large (e.g., 2147483647) giving the appearance of stream I/O. This
is not true for all compilers however.
On some compilers it is possible to set the record length as follows:
open(unit=6, recl = 2147483646)
On other compilers unit 6 is preconnected and the record length cannot be changed. (Thanks to Jon Richards of the USGS for this tip.)
Note that unit 6 and unit * are not necessarily the same. Although they both may point to the default output device, with non-advancing I/O, each could keep track of the current location in its own record separately. Therefore we advise choosing one default unit and sticking with it.
real function kinetic_energy(v) real, dimension(:), intent(in) :: v integer i ! THIS IS THE WRONG WAY real :: ke = 0.0 do i = 1, size(v) ke = ke + v(i)**2 enddo kinetic_energy = .5*ke end function kinetic_energy
real function kinetic_energy(v)
real, dimension(:), intent(in) :: v
integer i
! THIS IS THE RIGHT WAY
real :: ke
ke = 0.
do i = 1, size(v)
ke = ke + v(i)**2
enddo
kinetic_energy = .5*ke
end function kinetic_energy
Explanation
A local variable that is initialized when declared has an implicit
save attribute. ke is initialized only the first time the function is
called. On subsequent calls the old value of ke is retained. This is a
real suprise to C programmers.
To avoid confusion it is best to add the save attribute to such locally initialized variables explicitly, even though this is redundant.
program main real, dimension(5) :: x x = 0. ! THIS IS WRONG call incb(x) print *, x end program main subroutine incb(a) ! this is a fortran90 style subroutine real, dimension(:) :: a a = a + 1. end subroutine incb
Explanation
The subroutine incb uses a Fortran 90 style assumed shape array (containing
dimension(:)). Such routines must either be in a module, or have
an explicit interface wherever they are used. In this example, neither one was
true.
One correct way to call such procedures is to use an explicit
interface as follows:
program main
real, dimension(5) :: x
! THIS IS THE RIGHT WAY
interface
subroutine incb(a)
real, dimension(:) :: a
end subroutine incb
end interface
x = 0.
call incb(x)
print *, x
end program main
subroutine incb(a)
! this is a fortran90 style subroutine
real, dimension(:) :: a
a = a + 1.
end subroutine incb
If the routine is in a module interfaces are generated automatically and
do not need to be explicitly written.
! THIS IS ANOTHER RIGHT WAY
module inc
contains
subroutine incb(a)
! this is a fortran90 style subroutine
real, dimension(:) :: a
a = a + 1.
end subroutine incb
end module inc
program main
use inc
real, dimension(5) :: x
x = 0.
call incb(x)
print *, x
end program main
If interfaces are used, the interface MUST match the actual function.
program main real, dimension(5) :: x ! interface to Fortran 77 style routine interface subroutine inca(a,n) integer :: n ! THIS IS THE WRONG WAY real, dimension(:) :: a ! THIS IS THE RIGHT WAY real, dimension(n) :: a end subroutine inca end interface x = 0. call inca(x,5) print *, x end program main subroutine inca(a,n) ! this is a fortran77 style subroutine dimension a(n) do 10 j = 1, n a(j) = a(j) + 1. 10 continue return end
Explanation
The interface declaration must always match the actual subroutine
declaration. In this case, the interface statement refers to a
Fortran 90 style assumed shape array. The actual subroutine refers to
a Fortran 77 explicit shape array. The lesson here is: Interfaces to
Fortran 77 style routines must only use Fortran 77 style
constructs.
In this example, it is permitted to leave out the interface altogether since routines without interfaces are treated as Fortran77 style routines by default. However, if the interface is left out, the compiler will no longer check whether the arguments of calling procedures agree with the arguments listed in the interface.
subroutine first_sub(a,i)
real :: a
integer :: i
...
end subroutine first_sub
!
subroutine second_sub(i,a)
integer :: i
real :: a
...
end subroutine second_sub
So that one could define a generic function first_or_second
below:
interface first_or_second
module procedure first, second
end interface
This is NOT so.
Explanation
The reason is that Fortran 90 allows procedures
to be called by name (keyword) arguments. The following
real :: b
integer :: n
call first_or_second(i=n,a=b)
does not work because when called by keyword, first_sub and
second_sub are indistinguishable,
call first_sub(i=n,a=b)
call second_sub(i=n,a=b)
and therefore a generic function cannot be defined. A generic function must be able to distinguish its arguments by type AND by name.
The solution is to not use the same dummy argument name in both procedures.
For example, the following would work:
subroutine second_sub(i,aa)
integer :: i
real :: aa
...
end subroutine second_sub
Automatic arrays are automatically created on entry and deleted on exit from a procedure, and they are safest and easiest to use. Allocatable arrays require the user to manually create and delete them, and should only be used if automatic creation and deletion is not the desired behavior.
Pointers are the most error prone and should only be used when allocatable arrays are not possible, e.g., when one desires an array to be a component of a derived type.
In this example we are allocating a local_table on first entry that
is to be reused on subsequent entries.
subroutine local_pointer(this)
real, dimension(:) :: this
real, dimension(:), save, pointer :: local_table
! THIS IS THE WRONG WAY
if (.not. associated(local_table)) then
allocate(local_table(size(this)))
endif
local_table = ...
...
end subroutine local_pointer
subroutine local_pointer(this)
real, dimension(:) :: this
real, dimension(:), save, pointer :: local_table
! THIS IS THE RIGHT WAY
logical, save :: first_entry = .true.
if (first_entry) then
nullify(local_table) ; first_entry = .false.
end if
if (.not. associated(local_table)) then
allocate(local_table(size(this)))
endif
local_table = ...
...
end subroutine local_pointer
Explanation
When a pointer is declared its status is undefined, and cannot be
safely queried with the associated intrinsic. A second variable is
introduced to nullify the pointer on first entry so that its status
can be safely tested. This is not a problem in Fortran 95 which allows
one to nullify a pointer on declaration.
Note that the save attribute for local_table is necessary to guarantee that the array and the pointer status are preserved on subsequent entries. We recommend that the save attribute should always be used when pointers and allocatable arrays are allocated in procedures.
In this module we have created a private type which contains a
pointer and a public procedure to assign that pointer.
module assign_pointer_class
type mytype
private
real, pointer :: pr
end type mytype
interface assignment (=)
module procedure assign_pointer
end interface
contains
subroutine assign_pointer(this, a)
type (mytype), intent(out) :: this
real, target, intent(in) :: a
this%pr => a
end subroutine assign_pointer
end module assign_pointer_class
In this main program we intend to assign the pointer component x%pr to
the variable a, x%pr =>a. We cannot do so directly because the
components of mytype are private. One must use a public procedure to
do so. Furthermore, to simplify the syntax one might be tempted to use
an overloaded assignment operator (=).
program main
use assign_pointer_class
type (mytype) :: x
real :: a = 0
! THIS IS THE WRONG WAY
x = a
end program main
Don't give into this temptation! The only safe way to accomplish
this is to call the procedure directly.
program main
use assign_pointer_class
type (mytype) :: x
! THIS IS THE RIGHT WAY
real, target :: a = 0
call assign_pointer(x,a)
end program main
Explanation
The Fortran 90 standard says that the right hand side of an assignment
operator is an expression that may potentially only persist for the
duration of the call. In other words, x%pr could inadvertently point to
a temporary copy of the variable a.
Thanks to Henry Zongaro of IBM for pointing this out. (We never would have figured this one out on our own.)
Also, James Giles found a subtle point regarding this example. We did not include "target" in the declaration of the real variable "a" (this has been corrected above). In James' words:
"Notice that for this to really work, the actual argument, 'a', must be declared with the target attribute. You correctly declare the dummy argument in the assign_pointer routine with the target attribute, but the actual argument must also have that attribute (otherwise it's illegal for any pointer to be associated with it). Just a minor point..."
program main type mytype real, dimension(:), pointer :: p end type mytype type (mytype), pointer :: x ! BOTH OF THESE ARE THE WRONG WAY ! AND THE COMPILER WON'T CATCH IT ! nullify(x%p) ! allocate(x%p(5)) ! ONE SHOULD ALWAYS IMMEDIATELY NULLIFY THE PARENT POINTER ! OR ALLOCATE IT nullify(x) ! or allocate(x) ... ! THEN LATER NULLIFY OR ALLOCATE THE CHILD POINTER call child_construct(x,5) if (associated(x%p)) print *, x%p contains subroutine child_construct(this,len) ! child constructor for pointer within mytype ! if len is present, then allocate it, otherwise nullify it. ! mytype is assumed to be already nullified or allocated type (mytype), pointer :: this integer, optional, intent(in) :: len if (.not.associated(x)) allocate(x) if (present(len)) then allocate(x%p(len)) x%p = 0. else nullify(x%p) endif end subroutine child_construct end program main
Explanation
This example creates a pointer to a pointer to an array of reals where
the first pointer has not been allocated. For safety one should always
either allocate or nullify the parent pointer immediately after its
declaration. The child pointer cannot be allocated before the
parent. Since the child pointer may be allocated elsewhere in the
code, it is convenient to use constructor routines for this
purpose.
Each child constructor can safely allocate or nullify its pointers only when it can be sure that its parent's pointers have been allocated or nullified.