Finalisation in FORTRAN 2003 - fortran

According to Fortran Wiki the intel fortran compiler version 14 should support finalisation defined in FORTRAN 2003 standard. I tried to use this feature with ifort 14, but observed strange behaviour. Following example should show this:
module mtypes
implicit none
type mytype
integer, private :: nr
contains
final :: delete_mytype
procedure :: print_mytype
end type
contains
!> \brief Constructs a new mytype
!! \return The created mytype
!>
function init_mytype(number)
type(mytype) :: init_mytype
integer, intent(in) :: number
! allocate(init_mytype)
init_mytype = mytype(number)
print *, 'init mytype', number
end function
!> \brief De-constructs a mytype object
!>
subroutine delete_mytype(this)
type(mytype) :: this !< The mytype object that will be finalized
print *, 'Deleted mytype!', this%nr
end subroutine delete_mytype
!> \brief Print something from mytype object
!>
subroutine print_mytype(this)
class(mytype) :: this !< The mytype object that will print something
print *, 'Print something from mytype!', this%nr
end subroutine print_mytype
end module mtypes
program main
use mtypes
type(mytype) :: t1, t2
call t1%print_mytype()
call t2%print_mytype()
t1 = mytype(1)
call t1%print_mytype()
t2 = init_mytype(2)
call t2%print_mytype()
end program main
Within this complete example the type mytype is defined that only has one value nr. This type can be created using simple type constructor e.g. mytype(1) or the initialising function init_mytype. Also a subroutine print_mytype is defined that simply prints mytype%nr to stdout. Finally, the final routine delete_mytype should be used for finalisation, although in this example case it only prints some information to stdout.
This example gives following output:
Print something from mytype! 0
Print something from mytype! 0
Deleted mytype! 0
Print something from mytype! 1
Deleted mytype! -2
init mytype 2
Deleted mytype! 0
Deleted mytype! 2
Print something from mytype! 2
Line 1: Ok, t1 initialised with default value 0
Line 2: Ok, t2 initialised with default value 0
Line 3: Ok, after assignment of new object t1%mytype(1) the old version is deleted
Line 4: Ok, version with nr = 1 is printed
Line 5: Strange, where does a version with nr=-2 come from?
Line 6: Ok, version with nr = 2 is initialised
Line 7: Ok, after assignment of new object t2 = init_mytype(2) the old version is deleted
Line 8: Strange, t2 is finalized before call of t2%print_mytype()
Line 9: Strange, t2 is printed after finalisation
Is this strange behviour caused by some ifort bug or is this caused by wrong application of the finalization FORTRAN 2003 feature and I am doing something wrong?

What appears strange is actually the result of the rules on finalization. In Fortran 2008 4.5.6.3 ("When finalization occurs") the prompts for finalization are given.
Before coming to those, a word about initialization. You say
Line 1: Ok, t1 initialised with default value 0
The derived type component nr doesn't have default initialization, and there's no explicit initialization for t1, so your statement isn't true. In fact, t1%nr is undefined at this point. 0 just happens to be the result. This is important, as we see later.
Your code, with comments about finalization:
t1 = mytype(1) ! t1 finalized before assignment
call t1%print_mytype()
t2 = init_mytype(2) ! t2 finalized before assignment, after function
! init_mytype result finalized after assignment
call t2%print_mytype()
! No finalization before END PROGRAM (4.5.6.4)
Your lines 8 and 9 unexpected behaviour are not strange. In particular, call t2%print_mytype() occurs after the two finalization calls in the statement t2=init_mytype(2).
Now, where does the finalization from line 5 come from? And why -2? Remember that there is no initialization? -2 is an allowed result if a finalization occurs for an entity without assignment. Which entity is finalized?
Look in the function init_mytype returning a result of type mytype:
function init_mytype(number)
type(mytype) :: init_mytype ! No initialization of result
integer, intent(in) :: number
init_mytype = mytype(number) ! Result finalized before assignment
print *, 'init mytype', number
end function
To conclude, the following prompts occur in this program:
When an intrinsic assignment statement is executed, the variable is finalized after evaluation of expr and before the definition of the variable.
If an executable construct references a function, the result is finalized after execution of the innermost executable construct containing the reference.
As an aside, if you look at the draft Fortran 2008 standard (such as I did when I mistakenly copied the wrong prompt in an earlier revision of this answer) you may think: why aren't the results of the structure constructor finalized? This should happen twice: once directly in the program, and once indirectly through the call to init_mytype. But we see no such effect.
Consider the interpretation request "How many times are constructed values finalized?" and the corrigendum. Constructor results are considered to be not finalized, correcting a mistake in Fortran 2003. This may be relevant, as you do ask about Fortran 2003 (although ifort clearly implements the new rules).

Related

Class dummy argument for array of custom types stuck on -fcheck=bounds

I have the following simple Fortran code
program test
type vec
integer :: x(3)
end type
type(vec) :: v(2)
call sub(v)
contains
subroutine sub (v)
class(vec), intent(in) :: v(:)
integer :: k, q(3)
q = [ (v(1)%x(k), k = 1, 3) ] ! <-- fails here
end subroutine
end program
which, when compiled by GNU Fortran 11 (but not other versions) with -fcheck=bounds, fails with the error
At line 19 of file test.f90
Fortran runtime error: Index '3' of dimension 1 of array 'v%_data%x' above upper bound of 2
It look as if the compiler simply interchanged the lengths of x and v and this can be confirmed by changing the numbers.
When the word class is replaced by type, the problem goes away.
I believe that the code is valid as it is. Or is it violating some Fortran language restriction that results in this surprising behaviour?

Fortran EQUIVALENCE statement with array length from subroutine input

I'm modernizing some old Fortran code and I cannot get rid of an equivalence statement somewhere (long story short: it's mixed use is so convoluted it'd take too much work to convert everything).
I need the length of the EQUIVALENCEd arrays to depend on some input, like the following code:
program test_equivalence
implicit none
type :: t1
integer :: len = 10
end type t1
type(t1) :: o1
call eqv_int(o1%len)
call eqv(o1)
return
contains
subroutine eqv_int(len)
integer, intent(in) :: len
integer :: iwork(len*2)
real(8) :: rwork(len)
equivalence(iwork,rwork)
print *, 'LEN = ',len
print *, 'SIZE(IWORK) = ',size(iwork)
print *, 'SIZE(RWORK) = ',size(rwork)
end subroutine eqv_int
subroutine eqv(o1)
type(t1), intent(in) :: o1
integer :: iwork(o1%len*2)
real(8) :: rwork(o1%len)
equivalence(iwork,rwork)
print *, 'LEN = ',o1%len
print *, 'SIZE(IWORK) = ',size(iwork)
print *, 'SIZE(RWORK) = ',size(rwork)
end subroutine eqv
end program test_equivalence
This program will create 0-length arrays with gfortran 9.2.0. This is the output:
LEN = 10
SIZE(IWORK) = 0
SIZE(RWORK) = 0
LEN = 10
SIZE(IWORK) = 0
SIZE(RWORK) = 0
The same code will return Array 'rwork' at (1) with non-constant bounds cannot be an EQUIVALENCE object when compiled with gfortran 5.3.0, the warning disappears since gfortran 6.2.0, but the size of the arrays is always 0. So maybe compiler bug?
The source code is indeed not a valid Fortran program. To be specific, it violates the numbered constraint C8106 of Fortran 2018:
An equivalence-object shall not be a designator with a base object that is .. an automatic data object ..
Being a numbered constraint, the compiler must be capable of detecting this violation. If hasn't such a capability this is a deficiency in the compiler (a bug). Being "capable" doesn't mean doing so by default, so please look carefully to see whether there are options which do lead to this detection. Someone familiar with the internals of GCC can give further detail here.
As the source isn't a valid Fortran program, the compiler is allowed to consider the arrays of size zero if it has skipped the violation detection.

Could declaration of pointers to derived types be undefined?

I have a small code declaring a pointer to array of derived type which has a field that is an allocatable array of another derived type having a real variable as a field.
Using gnu fortran (8.2) I obtain different results for each location in the array or as a vector.
Using intel fortran (2019.4) compiler succeeded.
program test
implicit none
integer, parameter :: length = 2
real(8), dimension(length) :: a, b
integer :: i
type point
real(8) :: x
end type point
type stored
type(point), dimension(:), allocatable :: np
end type stored
type(stored), dimension(:), pointer :: std=>null()
allocate(std(1))
allocate(std(1)%np(length))
std(1)%np(1)%x = 0.3d0
std(1)%np(2)%x = 0.3555d0
do i = 1, length
write(*, "('std(1)%np(',i1,')%x = ',1e22.14)") i, std(1)%np(i)%x
end do
do i = 1, length
write(*, "('std(1)%np(1:',i1,') = ',2e22.14)") i, std(1)%np(1:i)%x
end do
a = std(1)%np(1:2)%x
b = [std(1)%np(1)%x, std(1)%np(2)%x]
if (norm2(a - b) .gt. 1d-3) then
write(*,*) 'failure'
else
write(*, *) 'success'
end if
end program test
the code terminates successfully, but using gfortran one obtains 'failure' on screen and inconsistent prints above and using Intel compiler one obtains 'success' on screen and consistent prints above.
It's not clear to me what your question is, unless it's the title. If so, no, pointers to derived types are fine. Your program correctly allocates std as an extent-1 array and then allocates std(1)%np(2). It then assigns to the x subcomponents of both np elements. Looks fine to me.
There are several things that could potentially cause "failure" - you should run the gfortran code in the debugger to see what is going wrong.
The problem presented in the code above was resolved in the following [link] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91077

Using derived type member as a do loop iteration variable [duplicate]

I was surprised that you cannot put a array member as the control variable of do loop like this:
program test
integer, dimension(2) :: i
do i(1) = 1, 3
do i(2) = 1, 3
! anything here
write(*, *) i
end do
end do
end program
My question is why it is not permitted?
Edit:
Or is it permitted but I am doing wrong?
The error message from ifort v 11.1 is:
test.f90(4): error #5082: Syntax error, found IDENTIFIER 'I' when expecting one of: ( % : . = =>
do i(1) = 1, 3
-------^
test.f90(4): error #5082: Syntax error, found ',' when expecting one of: <END-OF-STATEMENT> ;
do i(1) = 1, 3
---------------^
test.f90(5): error #5082: Syntax error, found IDENTIFIER 'I' when expecting one of: ( % : . = =>
do i(2) = 1, 3
-------^
test.f90(5): error #5082: Syntax error, found ',' when expecting one of: <END-OF-STATEMENT> ;
do i(2) = 1, 3
---------------^
test.f90(4): error #6535: This variable or component must be of a derived or structure type [DO]
do i(1) = 1, 3
----^
test.f90(4): error #6460: This is not a field name that is defined in the encompassing structure. [I]
do i(1) = 1, 3
-------^
test.f90(8): error #6099: An ENDDO statement occurred without a corresponding DO or DO WHILE statement.
end do
----^
test.f90(9): error #6099: An ENDDO statement occurred without a corresponding DO or DO WHILE statement.
end do
----^
The error message from gfortran V4.5.1 & 4.8.3 is:
test.f90:4.4:
do i(1) = 1, 3
1
Error: Unclassifiable statement at (1)
test.f90:5.4:
do i(2) = 1, 3
1
Error: Unclassifiable statement at (1)
test.f90:8.7:
end do
1
Error: Expecting END PROGRAM statement at (1)
test.f90:9.7:
end do
1
Error: Expecting END PROGRAM statement at (1)
Vladimir F's answer is correct, but we can stress a little more the pertinent point.
The quoted syntax rule for the do variable is
R819 do-variable is scalar-int-variable-name
and it's very important to note exactly what this means.
It is of course necessary for the do variable to be a scalar integer variable. In the case of the question the array element i(1) (and i(2)) is a scalar integer variable: array elements are variables of rank-0.
However, name is a further restriction. i(1) is not itself a name. We see the syntax rule
R303 name is letter [ alphanumeric-character ] ...
This restriction beyond scalar integer variable goes beyond array elements. In addition, the following may be variables which do not have corresponding names:
components of derived types;
functions with pointer results (a variable as of Fortran 2008, not before).
This means that the following is not allowed:
type t
integer i
end type t
type(t) x
do x%i=1,1 ! x%i is not a name
end do
end
Neither is
integer, target :: i
do f()=1,1
end do
contains
function f()
integer, pointer :: f
f=>i
end function
end
However, as noted in chw21's answer there is success with using an associate construct:
type t
integer i
end type
type(t) x
integer n(1)
associate (i=>x%i, j=>n(1))
do i=1,1
do j=1,1
end do
end do
end associate
end
Although x%i and n(1) are not names, the associate construct does create names:
R803 associate-stmt is [associate-construct-name :] ASSOCIATE
(association-list)
R804 association is associate-name => selector
Note that the associate entity being simply a variable is not sufficient.
Equally, pointers are allowed, if there is a name:
type t
integer i
end type
type(t), target :: x
integer, target :: n(1)
integer, pointer :: i, j
i => x%i
j => n(1)
do i=1,1
do j=1,1
end do
end do
end
Again, i and j here are names.
For interest, the NAG compiler marks using pointer and associate entities as do variables as "questionable". Indeed, one has to take extra care to avoid changing the loop variable.
Sorry for my first wrong answer.
The restriction follows from the rules of the language:
Fortran 2008 (ISO/IEC 1539-1:2010) 8.1.6.2:
R818 loop-control is, do-variable = ...
R819 do-variable is, scalar-int-variable-name
C812 (R819) The do-variable shall be a variable of type integer.
Therefore yes, only a scalar variable name is permitted at the position of the loop control variable.
If you ask why the rules of the language are like this, you have to ask the authors of the standard, the SC22/WG5 and X3J3, but I would guess it is connected with the necessity of syntactic unambiguity in the fixed-source form. In the fixed source form spaces are not significant and it is difficult to come up with an unambiguous grammar.
Fortran 2003 and later has a construct called an Associate block, where, inside this block, you can associate a name with any expression. In your case, it looks a bit like this:
program test
integer, dimension(2) :: i
associate (x => i(1), y => i(2))
do x = 1, 3
do y = 1, 3
! anything here
write(*, *) i
end do
end do
end associate
end program
This updates i inside the double loop.
(Note: Until #VladimirF confirmed it in a comment below, I wasn't certain whether this was standard conform. Thanks)

How to create functions in Fortran?

I'm sure the solution to this is extremely basic, but I'm having a hard time figuring out how to use functions in Fortran. I have the following simple program:
PROGRAM main
IMPLICIT NONE
INTEGER :: a,b
a = 3
b = 5
PRINT *,funct(a,b)
END PROGRAM
FUNCTION funct(a,b)
IMPLICIT NONE
INTEGER :: funct
INTEGER :: a,b
funct = a + b
END FUNCTION
I've tried several variations of this, including assigning a data type before FUNCTION, assigning the result of funct to another variable in the main program and printing that variable, and moving the FUNCTION block above the PROGRAM block. None of these worked. With the current program I get an error on line 6 (the line with the PRINT statement):
Error: Return type mismatch of function 'funct' (UNKNOWN/INTEGER(4))
Error: Function 'funct' has no IMPLICIT type
From all of the guides I've tried, I seem to be doing it right; at least one of the variations, or a combination of some of them, should have worked. How do I need to change this code to use the function?
Simply putting the function in the file will not make it accessible to the main program.
Traditionally, you could simply declare a function as external and the compiler would simply expect to find a suitable declaration at compile-time.
Modern Fortran organizes code and data in "modules". For your purpose, however, it is simpler to "contain" the function within the scope of the main program as follows:
PROGRAM main
IMPLICIT NONE
INTEGER :: a,b
a = 3
b = 5
PRINT *,funct(a,b)
CONTAINS
FUNCTION funct(a,b)
IMPLICIT NONE
INTEGER :: funct
INTEGER :: a,b
funct = a + b
END FUNCTION funct
END PROGRAM main
A simpler solution can be the following code
PROGRAM main
IMPLICIT NONE
INTEGER :: a,b, funct
a = 3
b = 5
PRINT *,funct(a,b)
END PROGRAM
FUNCTION funct(a,b)
IMPLICIT NONE
INTEGER :: funct
INTEGER :: a,b
funct = a + b
END FUNCTION
where the only difference is in the third line, where I have declared funct as an integer. It compiles and it prints 8 as result.