Difference between SAVE, PROTECTED and PARAMETER for attributes module data entities - fortran

If I want to prevent module data from being changed during program execution, I seem to have at least three options in Fortran:
1. using the SAVE statement
module mymod
implicit none
save
integer :: i = 1
end mymod
2. using the PROTECTED attribute
module mymod
implicit none
integer, protected :: i = 1
end mymod
3. using the PARAMETER attribute
module mymod
implicit none
integer, parameter :: i = 1
end mymod
What are the differences and implications of the three options?

This answer addresses the non-subtle aspects of the use of the entities named i. There are a few other considerations to be made in more complicated cases. It also uses the term variable definition context. Loosely speaking, this means where a variable may appear such that its value could change. This would be things like being the left-hand side of an assignment; appearing as a do variable or corresponding to an intent(out) argument.
i may appear in a variable definition context whenever it is accessible.
i (as a non-pointer object), where it is accessible, can appear in a variable definition context only in the scope of its module or descendants of that module.
i can never appear in a variable definition context: it is a constant not a variable.
The save attribute (in the current standard any module variable has this attribute; even i in the second example is saved) does not control modification.

Related

Can Fortran PURE functions use global parameters?

It seems to me the what is called a pure function in Fortran is not considered pure enough for those who use functional programming. So here is my question. Suppose I have the following code:
MODULE basics
IMPLICIT NONE
INTEGER, PARAMETER :: dp = kind(1.0d0)
REAL(dp), PARAMETER :: PI=3.1415926535897932_dp
REAL(dp), PARAMETER :: earthEquatorialRadius=6378.137_dp
END MODULE basics
MODULE myFunctions
USE basics
IMPLICIT NONE
PURE REAL(dp) FUNCTION sphericalArc(angleInRadians)
REAL(dp),INTENT(IN) :: angleInRadians
sphericalArc= 2.0*PI*earthEquatorialRadius*angleInRadians
END FUNCTION sphericalArc
END MODULE myFunctions
The function sphericalArc has no side effects, so it's pure in that sense, but it uses global constants. It's true that the parameters PI and earthEquatorialRadius can be defined inside the function but this is undesirable since I would like to use these in other functions and subroutines. It's going to be even more tedious to make the dp type defined in each function or procedure.
So from Fortran's perspective is a function that uses global parameters defined outside of the function still considered pure and can be called from a do concurrent loop?
If a Fortran procedure (function or subroutine) has the pure prefix in its definition then it is a pure procedure in the sense that Fortran uses it. It can then be used in places where there is a restriction of purity. A procedure with prefix elemental and without the prefix impure is also pure.
To be allowed to be specified as pure, the procedure is subject to a number of constraints, but it is necessary for the compiler to diagnose any violation of these constraints when pure is given.
There is no constraint that a named constant from another module (or other scope) may not be referenced.
As motivation for purity in Fortran, the standard (F2008, Note 12.49) offers:
The above constraints are designed to guarantee that a pure procedure is free from side effects (modifications of data visible outside the procedure)
Referencing a named constant is not modification of data visible outside the procedure.
From this documentation it should be okay to use a global variable as long as it is a parameter (so the value does not change).
The execution_part and internal_subprogram_part of a pure procedure
cannot refer to a dummy argument with an INTENT(IN), a global variable
(or any object that is storage associated with one), or any subobject
thereof, in contexts that may cause its value to change: that is, in
contexts that produce side effects.

variable length array in derived type

I am mostly doing scientific programming in Python and do not have a whole lot of Fortran (90/95) experience. For one of my projects I want to define a derived type and overload a bunch of operators for that type. Critically, I'd like one of the variables of the derived type to an array of variable length; at least, I need two different lengths in different parts of the code. How can I best achieve this efficiently and avoiding code duplication?
My first approach was to use an allocatable array but that involved several allocate statements throughout the code including the overloaded operators. It also led to difficulties when using the code in an MPI application.
My current approach is two define a type of the same name in two separate modules and use one or the other in different parts of the code. The overloaded operators can be shared using a header file (mytype_operators.h in the example below).
module mod1
type mytype
real :: x1
real,dimension(1) :: x2
end type mytype
#include "mytype_operators.h"
end module mod1
module mod2
type mytype
real :: x1
real,dimension(10) :: x2
end type mytype
#include "mytype_operators.h"
end module mod2
Unfortunately, there is one module in the code with subroutines that I would like to use for both types. Currently I have two copies of that code; one with "use mod1", the other with "use mod2". Can I improve this and avoid the code duplication?
Your case is very suitable for using a Fortran feature introduced in the 2003 standard (and adopted much later by compilers) named parameterized derived types. First of all, you should check the compliance status of your compiler to know if it's fully supported.
This feature allows you to pass custom parameters when declaring or constructing a derived-type, so internal functionality will be adjusted accordingly. They are good for having different behaviour alternatives grouped in a single type name, possibly with considerable coding or storage differences. There are 2 types of parameters:
kind parameters behave much like the kind specifier of intrinsic types. Kind parameters of all variables must be known at compile time and are treated practically as constant values. The convenience is that you could change it easily (in code time) by altering just a value in the declaration or construction. This is commonly used for specializing the kind of components of intrinsic type.
len parameters behave much like the len specifier of intrinsic character type. You can define len parameters at compile time or runtime, and a len parameter of a variable cannot change unless you declared it allocatable. Moreover, you can have arguments with assumed len-parameters in procedures, and avoid code verbosity. This is commonly used as a "length" or "dimension" parameter for a derived type, because you can use them in the declaration of array bounds and character length.
In general, type parameters are used to mimic the functionality of intrinsic types in derived types, but you could also get "creative" and use it for other things, like the dimension-space of a transformation-matrix type; for a custom "union type" (like an enumeration); as the nature of a physical quantity in a "units of measurement" data-type (a real value annotated with "mass" unity is not directly compatible with a "temperature" one, but they can be handled pretty much the same way in the code); the "arity" of a tuple type...
module mod1
type :: mytype(n)
integer, len :: n
real :: x1
real, dimension(n) :: x2
end type mytype
contains
! your operations here...
end module mod1
And use it like this:
program test_pdt
use mod1
implicit none
type(mytype(10)) :: mt10
type(mytype(1)) :: mt1
integer :: i
mt10%x1 = 40.0
mt10%x2 = [(0.5 * i, i = 1, 10)]
mt1 = mytype(1)(20.0, [30.0])
call sub(mt10)
call sub1(mt1)
contains
subroutine sub(m)
! accepts values with any "n" parameter
type(mytype(*)) :: m
! you can also use them in declarations
integer, dimension(m%n + 1) :: y
type(mytype(m%n)) :: w
print *, m%n, w%n, size(y)
end
subroutine sub1(m)
type(mytype(1)) :: m ! only accepts values with n=1
print *, m%x1, m%x2, m%n
end
end
Warning:
This is feature, despite of having been announced many years ago, was just recently added to most compilers, and you should be aware that there are still some bugs in implementation. You should probably be fine with regular use, but I often face false syntax errors in some corner cases, and even ICE sometimes.

error when calling a subroutine within subroutine

Hi I have tried to create a minimal, complete, and verifiable example sample code below to emphasize the one error message I am getting. The error is "Type Mismatch in argument 'func0' at (1); passed REAL(4) to COMPLEX(4).
I indicated in the code where the error message from (1) is. It occurs when I try to call a subroutine within another subroutine.
I originally tried to add implicit none into Sub2, however then I get an error message saying func0,func1 do not have implicit types.
I tried to follow the logic of this post : How to call and use a subroutine inside another subroutine in fortran?
Module Sample
integer :: n,m
contains
subroutine Sub1(func0,func1)
implicit none
complex, dimension(-10:10, -10:10), intent(inout) :: func0,func1
complex, dimension(-10:10, -10:10) :: Deriv0,Deriv1
do while (100 > 0.000001)
Deriv0 = Deriv(func0)
Deriv1 = Deriv(func1)
end do
end subroutine Sub1
subroutine Sub2(func3)
!implicit none : if this line is not commented out, I still get error messages saying func0,func1 do not have implicit types
real,dimension(0:20), intent(inout) :: Func3
call Sub1(func0,func1) !error message from here, this is line (1)
end subroutine Sub2
function Deriv(func)
implicit none
complex, dimension(-10:10, -10:10) :: func, Deriv
do n=-9,9
do m=-9,9
Deriv(n,m) = func(n+1,m)-2*func(n,m)
end do
end do
end function Deriv
End Module Sample
How can I fix this error? Thanks.
There are a number of concepts here we concern ourselves with: scoping; association; and inheritance.
In the code of the question there are four scoping units: the module sample and the three procedures (two subroutines and one function). These are all distinct, but some information is shared between them.
Looking first at the implicit statement. In the module there is no implicit so default typing rules apply in the module's scoping unit. (Although nothing in the module is implicitly typed - the module variables and the function are all explicitly declared.) sub1 and deriv each have implicit none so the typing rule (no implicit typing) is stated clearly there.
With implicit none specified in sub2 there is a compiler complaint about no explicit type declaration of func0 and func1; without implicit none the scoping unit sub2 inherits the typing rules of its host (the module) and so func0 and func1 are real.
You can read about scoping units and typing rules in another question and its answers. In summary, put implicit none in the module.
This typing of func0 and func1 leads us to another aspect of scoping. sub1 and sub2 are entirely different scoping units. The only way those two subroutines can share knowledge about declarations is through association of one form.
There are two forms of association going on here: host association and argument association.
Host association is that each subroutine has access to the variables n and m. They don't reference those variables so let's ignore them. Host association also gives an explicit interface of sub1 in sub2 which allows the compiler to complain about the type mismatch.
In the scoping unit of sub2 there is no explicit declaration of func0 and func1. This is an error with implicit none in force; with default implicit typing rules they are real scalar variables or functions with real scalar results. If you want them to be complex arrays you are just going to have to declare them as such.
Argument association comes about in the following way. We associate the dummy arguments of sub1 with the actual arguments of sub2. The crucial thing here is association: two distinct things happen to refer to the same object. The two procedures don't share anything that isn't explicitly stated in each. To be able to have an actual argument associated with those dummy arguments something appropriate has to exist in the scope of sub2. Currently nothing does.
In short: you need to have a suitable declaration of func0 and func1 in sub2. These may be local variables or dummy arguments, depending on how you want the program to flow.
(Disclaimer: I don't actually know Fortran. This answer is a WAG.)
In your Sub2 subroutine, neither func0 nor func1 are declared, and they're not parameters. Unlike the other parts of your code, Sub2 does not contain an implicit none directive, so the compiler assumes you intended func0 to be a REAL variable, which then leads to a type error (because Sub1 requires a COMPLEX variable).
I can't tell you how to fix this because your code never calls Sub2 anywhere, but presumably you have to get two COMPLEX variables from somewhere to pass to Sub1.

What's the difference between a named constant and a static (SAVE) variable, apart from being guaranteed immutable?

Comparing
INTEGER, SAVE :: foo = 3
to
INTEGER, PARAMETER :: foo = 3
in what ways do they behave different? Obviously the latter will trigger a compiler error when somebody attempts to mutate foo, but is this just like the const keyword in C / C++ or does it also imply something about storage location etc.?
The parameter attribute is used to denote a named constant that is set at compile-time and cannot be changed at run-time. As such, it is similar to the const keyword. To cite the Fortran 2008 Standard, Cl. 5.3.13 "PARAMETER attribute":
1 The PARAMETER attribute specifies that an entity is a named constant. The entity has the value specified by its constant-expr , converted, if necessary, to the type, type parameters and shape of the entity.
[...]
2 A named constant shall not be referenced unless it has been defined previously in the same statement, defined in
a prior statement, or made accessible by use or host association.
The save attribute causes a variable to keep state after it gets out of scope, e.g. between consecutive calls to a subroutine or inside a module. Other than that, it behaves like a normal variable and can be changed at run-time. The Fortran 2008 Standard, Cl. 5.3.16 "SAVE attribute" states that
1 The SAVE attribute specifies that a local variable of a program unit or subprogram retains its association status, allocation status, definition status, and value after execution of a RETURN or END statement unless it is a
pointer and its target becomes undefined (16.5.2.5(5)). If it is a local variable of a subprogram it is shared by all instances (12.6.2.4) of the subprogram.
A constant is not a variable in the first place. It does not have any storage (conceptually). You cannot ask for its address. You cannot put it in context where a variable is required. You cannot point pointers at it. You can only use it in expressions.
For example consider
INTEGER, SAVE :: foo = 3
INTEGER, PARAMETER :: bar = 3
then
call sub(foo)
passes the variable foo to the subroutine, while
call sub(bar)
computes an expression (rather simple one), stores its value somewhere, and passes it to the subroutine.
You can also do
INTEGER, PARAMETER :: bar = 3
INTEGER, SAVE :: foo = bar
while
INTEGER, SAVE :: foo = 3
INTEGER, PARAMETER :: bar = foo
won't work. A constant value requires a constant expression.

Declaration and initialization of local variables in Fortran PURE FUNCTIONs

I have a function that looks like this:
PURE FUNCTION simulate(initial_state, time_specification)
TYPE(ocean), INTENT(IN) :: initial_state
TYPE(simulation_time), INTENT(IN) :: time_specification
TYPE(ocean) :: simulate
REAL :: t = 0.0
! etc
END FUNCTION simulate
gfortran 4.8.1 informs me that
REAL :: t = 0.0
1
Error: Initialization of variable at (1) is not allowed in a PURE procedure
As I understand it, I should be able to use local variables within pure functions as long as they do not have the SAVE attribute. So what am I doing wrong?
Under modern Fortran initialization implies SAVE. From F2008 5.2.3
Explicit initialization of a variable that is not in a common block implies the SAVE attribute, which may be confirmed by explicit specification.
You can use local variables, but just
real t
t = 0
which isn't initialization.
Beware! The initializing of variables during declaration implies the save attribute! This violates the pure condition. See here for details.
Better initialize the variable in your code later on...
REAL :: t = 0.0 is not pure, because it takes effect only the first time the function is called.