Array terminology can be a bit daunting in Fortran. The first thing to realize is the difference between an actual argument, a variable for which a procedure has to allocate some memory, and a dummy argument, placeholders for actual arguments passed along by the calling procedure. If a variable is in a procedure's argument list, it is a dummy argument.
So, as for actual arguments, there are two kinds of arrays:
- explicit-shape, e.g.
<type> :: A(3,6)
- deferred-shape, e.g.
<type>, <allocatable|pointer> :: A(:,:,:)
A deferred shape must have an allocatable
or pointer
attribute.
When it comes to dummy arguments, there are also two kinds of arrays:
- assumed-size, e.g.
<type> :: A(4,5,*), B(1:2,4:*), C(m,n)
- assumed-shape, e.g.
<type> :: A(:,4:)
The actual and dummy arguments are not related in any way, so don't mix them. Also note that there exist something called automatic arrays, these look exactly like assumed-size arrays with dummy variables as sizes (C(m,n)
), but don't appear in the argument list, so they are not dummy arguments.
For the assumed-size array, the last dimension's upper bound should be left unspecified (the *
), other than that lower+upper bounds can be specified, including variables passed along to the procedure. Think of it as an array for which you re-specify the entire layout, irrespective of the actual argument. This allows you to do things like:
program toby
integer, parameter :: n = 10
real :: a(n**3)
call my_sub(a,n)
end program
subroutine my_sub(a,n)
integer, intent(in) :: n
real, intent(inout) :: a(n,n,*)
...
end subroutine
The other dummy argument, the assumed-shape, only allows you to specify lower bounds, as it gets its size info from the actual argument. This means you also can't redefine the dimensionality, and you need an explicit interface (e.g. via a module). This makes it more stringent, and also unnecessary to pass along size information with the array.
program toby
integer, parameter :: n = 10
real :: a(n,n,n)
call my_sub(a)
contains
subroutine my_sub(a)
real, intent(inout) :: a(:,:,:)
integer :: n
n = size(a,1)
...
end subroutine
end program
You can read about it in much more detail here I find it to be an ideal reference.
Last but not least, since you mention python, don't be to eager to apply python-like array slicing in Fortran, as it can cause the use of temporary arrays, which can slow down the program. You can use -fcheck=array-temps
with gfortran to warn for that. Furthermore, even though elemental operations on whole arrays are recommended for efficiency (e.g. A=A+1
in using arrays efficiently), don't misinterpret that as "writing very concise code is good for efficiency". The latter is of course not (necessarily) true.