Declaration and initialization of local variables in Fortran PURE FUNCTIONs - fortran

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.

Related

How do variable declarations within types work in Fortran?

I'm trying to learn Fortran, and I've found that there aren't very many tutorials out there (probably due to it being an old language). The ones I have found are vague and undescriptive, and as I've gone into more complex things it has become harder and harder to guess what said tutorials are saying.My current issue is with creating types. The tutorial contains examples such as:
module m_shapes
implicit none
private
public t_square
type :: t_square
real :: side
contains
procedure :: area ! procedure declaration
end type
contains
! Procedure definition
real function area(self) result(res)
class(t_square), intent(in) :: self
res = self%side**2
end function
end module m_shapes
This compiles fine, so I know it works.
When I try to do something similar like this:
program type_test
implicit none
type :: thingy(a)
real :: a
end type
end program
It doesn't compile with errors like "The component at (1) that appears in the type parameter list at (2) has neither the KIND nor LEN attribute"
The tutorial I found does not explain types well enough, and I've tried things like real,kind :: a = kind(0.0), but to no avail. Does anybody know what's wrong?
Thanks in advance.
You did not explain, what you actually want to do. Or your words are not nearly clear enough. We can tell you why your attempt produces the error, but I have no idea what you actually want to do.
Perhaps you just wanted
program type_test
implicit none
type :: thingy
real :: a
end type
end program
without the (a)? That declares a simple type with one component. But hard to guess if this is what you wanted and what you tried with the (a).
It does not declare any variable with that type. That is done using
type(thingy) :: var
The syntax
type :: thingy(a)
real :: a
end type
attempts to declare a parametrized derived type. These types can depend on a kind or length parameter. These parameters must be integers. If it is a kind parameter, it allows to declare variables of the type with varying values of these parameters. Then the kind of some components of the type (you know what kind is, right? Fortran 90 kind parameter ) get their kind according to the value of the parameter. If it is a length parameter, it allows the length of some array or string components of the derived type to be parametrized - set during the variable declaration.
These parameters that appear in the parenthesis must be integer components and must have the kind or len attribute.
For example
type :: param_type(k,l)
integer, kind :: k
integer, len :: l
real(kind=k), dimension(l) :: array
end type param_type
type(param_type(kind(1.), 10)) :: o_sp_10
type(param_type(kind(1.d0), 20)) :: o_dp_20
The values of the parameters are set during the declaration of those o_sp_10 and o_dp_20 objects. I do not want to go into more details.

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

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.

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.

Does the finalization routine need to be elemental in order to be called on the elements of allocatable array that goes out of scope?

If I have an allocatable array of a finalizable derived type, will the finalizer be called on every individual element when the array goes out of scope?
Here is a small code example that illustrates the question:
module LeakyTypeModule
implicit none
private
type, public :: LeakyType
real, pointer :: dontLeakMe(:) => null()
contains
procedure :: New
final :: Finalizer
end type
contains
subroutine New(self, n)
class(LeakyType), intent(out) :: self
integer , intent(in) :: n
allocate(self%dontLeakMe(n))
self%dontLeakMe = 42.0
end subroutine
subroutine Finalizer(self)
type(LeakyType), intent(inout) :: self
if (associated(self%dontLeakMe)) deallocate(self%dontLeakMe)
end subroutine
end module
program leak
use LeakyTypeModule
implicit none
type(LeakyType), allocatable :: arr(:)
allocate(arr(1))
call arr(1)%New(1000)
deallocate(arr)
end program
Note that this program leaks the dontLeakMe array allocated in the New() method of LeakyType. At first this was a bit surprising for me but, then I discovered that the problem can be fixed by declaring the finalizer elemental. Both gfortran and ifort behave in the same way, so I assume this behaviour is following the Fortran 2003 standard.
Can anyone confirm this? To be honest I have a hard time time understanding what the standard says on this particular point.
Right now I also can't see much use in not declaring all my finalizers elemental. Does this have any application I'm overlooking?
The rules for determining whether a final procedure is invoked, and which final procedure is invoked, are the same as for resolution of generic procedures in terms of rank matching requirements.
Noting that the question is tagged Fortran 2003...
Elemental procedures in Fortran 2003 and prior have to be PURE. If your finalizer needs to do something that is incompatible with the pure attribute (which is reasonably common) then the finalizer cannot be elemental, and you need to write the rank specific variants.
Fortran 2008 introduces the concept of IMPURE ELEMENTAL, which is quite handy for writing finalizers.

Fortran derived type in common: initialization?

I got troubles with this common:
COMMON /REDCOM/ DPREC,NITMA,INDIC,NBERR,NCAR,KMOTLU,
& REDVAR,MOCDER(2)
COMMON /REDCO1/ CTEXT
C
type(double_st) :: DPREC
INTEGER :: NITMA,INDIC,NBERR,NCAR,KMOTLU,REDVAR,MOCDER
CHARACTER(72) :: CTEXT
CHARACTER(4) :: CTEXT4
C
EQUIVALENCE (CTEXT,CTEXT4)
The double_st derived type is:
type double_st
sequence
real(kind(0.d0)) :: x,y,z
integer :: acc = -1
end type double_st
Trying to compile some code including this common, I get:
ifort:
./REDCOM.INC(1): error #6005: A derived type object in a COMMON block shall not have default initialization [DPREC]
COMMON /REDCOM/ DPREC,NITMA,INDIC,NBERR,NCAR,KMOTLU,
----------------------^
gfortran:
REDCOM.INC:1.27:
Included at m_abaq4.f:90:
COMMON /REDCOM/ DPREC,NITMA,INDIC,NBERR,NCAR,KMOTLU,
1
Error: Derived type variable 'dprec' in COMMON at (1) may not have default initializer
Being not very familiar with Fortran, I don't understand what the problem is, or how to solve it (I tried googling with no success). If I use a REAL(8) instead of a double_st, everything works fine.
Could someone help me on this?
From the line
integer :: acc = -1
strip off the trailing
= -1
to leave
integer :: acc
recompile, and see what happens. The error message suggests that a program can't initialise a derived type component and use variables of that derived type in common statements. 'Initialize' is used in the Fortran standards to mean, precisely, the setting of a variable (or element) 's value in its declaration.
In my (draft) version of the Fortran 2008 standard constraint 506 on rule 503 prohibits initialization of components of variables of derived type used in common blocks. This prohibition doesn't seem to apply to initialization of variables of intrinsic types, hence the compiler's acceptance of the code when the variable is of type real(8).
As for using derived types in common blocks, that's mixed-paradigm programming if ever there was such a thing !
I'm saying much the same as in High Performance Mark's answer, but hopefully with a little more elaboration. After that answer's edit I actually diverge a little.
Having the type declaration
type double_st
sequence
real(kind(0.d0)) :: x,y,z
integer :: acc = -1
end type double_st
involves default initialization. That's the acc=1 part: see Fortran 2008 4.5.4.6. It isn't just the component that is default initialized but the whole type.
There is a constraint (C5105, in 5.7.2.1) which says that
If a common-block-object is of a derived type, the type shall have the BIND attribute or the SEQUENCE attribute and it shall have no default initialization.
This is what the compilers complain about. Using a real(kind(0d0)) (or real(8)) doesn't violate this constraint. Intrinsic types (such as that real) cannot have default initialization, but they can have explicit initialization (such as real :: hello = 1.). There are some restrictions on the use of an explicitly initialized object (such as C506 mentioned in the other answer), but the question isn't clear enough on that point for me to comment further.