I have a following code, with an abstract type, inherited type and a short program, where I'm creating an object and storing it in an array.
module m
implicit none
type :: container
class(a), allocatable :: item
end type container
type, abstract :: a
integer, public :: num
end type a
type, extends(a) :: b
integer, public :: num2
end type b
end module m
program mwe
use m
implicit none
class(a), allocatable :: o1
class(container), allocatable :: arr(:)
o1 = b(1, 2)
allocate(arr(2))
arr(1) = container(o1)
select type(t => o1)
type is(b)
write(*,*) t%num, t%num2
end select
select type(t => arr(1)%item)
type is(b)
write(*,*) t%num, t%num2
end select
end program mwe
The problem is, that the output looks like this:
1 2
1 0
As can be seen, the same variable stored in the array has the second variable nullified. Why is that happening? Is it because the array is of type a
, which only contains the first variable?
I'm compiling the code with ifort version 18.0.3
.
As with ripero's answer one could say that any output from the program is valid. However, we can make a simple modification to the code to make it correct Fortran.1 This answer is concerned with this modified version.
I would call this unexpected output and seek the help of the compiler vendor.
Using a structure constructor with polymorphic allocatable components is one of those new areas in Fortran. Compilers may take a while to catch up or do it correctly.
I have tested your code with Intel Fortran 18.0.2 and see the same output.
For your question
Is it because the array is of type a
, which only contains the first variable?
No: in the select type
part with the output t
is a non-polymorphic entity of type b
.
You may work around this problem by avoiding using the structure constructor:
arr(1)%item = o1
I also see that Intel compilers before 18.0.2 do something different still.
1 With the declaration
class(container), allocatable :: arr(:)
arr
is polymorphic and allocatable. As ripero notes, this means that arr(1)
, the element of arr
is polymorphic. However, as an array element, arr(1)
is not itself polymorphic and so may not be on the left-hand side of an intrinsic assignment statement. We can change the code in two ways: provide defined assignment, or make arr
not polymorphic. In the code of the question there seems no reason to have the container polymorphic, so I'll consider
type(container), allocatable :: arr(:)
Further, as discussed in comments on the question, if you wish to work with gfortran 8, or earlier, to see what happens, you should also modify the code in the question so that the definition of the derived type container
comes after the definition of the derived type a
.
I believe
arr(1) = container(o1)
is invalid Fortran 2008. This is an intrinsic assignment statement, but section 7.2.1.2 of the standard says that
In an intrinsic assignment statement, (1) if the variable is polymorphic it shall be allocatable and not a coarray.
As far as I can see, arr(1)
is polymorphic but not allocatable, so a standards-compliant compiler should issue an error and abort compilation.
If my reasoning is correct, the fact that Intel Fortran compiler compiles this code is a compiler bug and should be reported to Intel.