2

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.

4
  • "arr(1)%item = o1" works for gfortran-8.1, tio.run/… but the original code gives "Error: Nonallocatable variable must not be polymorphic in intrinsic assignment at (1)" Commented Jun 8, 2018 at 10:38
  • @roygvib, in that linked code you reordered the definitions of the derived types (container after a). Is that because gfortran 8 doesn't yet support the order in the question? Commented Jun 8, 2018 at 12:09
  • Yes, gfortran gives the following error if "container" is above "a" (result with OP's order) (You can modify the code there and push "Run (>)" button above :) Commented Jun 8, 2018 at 13:00
  • Interesting, thanks, @roygvib. I had read that gfortran 8 supports "recursive allocatable components" (the Fortran 2008 feature), so it surprised me that it doesn't accept the original order. Commented Jun 8, 2018 at 13:05

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Good point, but I wouldn't call it a compiler bug. This is a constraint on the program not the compiler. [QoI issue, perhaps, in that a diagnostic is missing.] It's worth mentioning that there's no reason on the code we see for arr to be polymorphic (and indeed, changing that doesn't resolve the unexpected output).
My understanding was that the word "shall" in the standard establishes requirements that the processor must satisfy...
Now that's the basis of an interesting question! The standard defines both what a Fortran program may look like and how a Fortran program should be interpreted. On the whole the restrictions are on programs, but where you see things like "C713" that means a compiler must be able to detect violations of a stated constraint on the program. More widely, a Fortran processor isn't judged on how it treats non-Fortran programs. See the Overview section of the standard for more detail.
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 Comments

The container type has a single scalar component item, of a type with only one integer component. Isn't it expected that an object arr(1) of the container class will only be able to store one integer, and an attempt to print a second component will give an arbitrary value (probably due to an out-of-bounds memory access)?
The component item is polymorphic, declared type a. In our example it has dynamic type b which has indeed two components, because that was the dynamic type of o1 in the structure constructor which was assigned to arr(1). Any attempt to print a component num2 of an object of declared type a should be detected as a violation by the compiler and not be compiled. However, the type guard means t is of declared type b.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.