Search code examples
arraysfortranintel-fortranfortran2008

Variables being deleted in Fortran Arrays?


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.


Solution

  • 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.