Variables being deleted in Fortran Arrays?

2019-07-21 22:26发布

问题:

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.

回答1:

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.



回答2:

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.