2

I'm trying to build an allocatable array with polymorphic elements. A minimal example is the following :

program PolyArray

implicit none

type basetype
    integer :: ib
end type basetype

type, extends(basetype) :: exttype1
    real    :: r1
end type exttype1

type, extends(exttype1) :: exttype2
    real    :: r2
end type exttype2

type arraytype
    class(basetype), allocatable :: comp
end type arraytype

type(arraytype), dimension(:), allocatable :: ary
integer :: N, i 

N = 5
allocate (ary(N))
do i=1,N; if (mod(i,2)==0) then
    allocate(exttype2::ary(i)%comp)
     else if (       i==1) then
    allocate(basetype::ary(i)%comp)
        else
    allocate(exttype1::ary(i)%comp)
end if; end do

do i=1,N; select type (this=>ary(i)%comp)
    type is (basetype)
        write(*,*) i, "is basetype"!, "%ib =", ary(i)%comp%ib
    type is (exttype1)
        write(*,*) i, "is exttype1"!, "%r1 =", ary(i)%comp%r1
    type is (exttype2)
        write(*,*) i, "is exttype2"!, "%r2 =", ary(i)%comp%r2
    class default
        write(*,*) i, "is unknown type !"
end select; end do

end program PolyArray

Now, the code above works fine and prints out (as expected) :

           1 is basetype
           2 is exttype2
           3 is exttype1
           4 is exttype2
           5 is exttype1

The problem is, however, once I try to access the component of each extended type (e.g. r1 of exttype1) by uncommenting the commented part of each write(*,*) line, my compiler (gfortran 7.5.0) gives the following error :

         write(*,*) i, "is exttype1", "%r1 =", ary(i)%comp%r1
                                                            1
Error: 'r1' at (1) is not a member of the 'basetype' structure
poly.f90:40:60:

         write(*,*) i, "is exttype2", "%r2 =", ary(i)%comp%r2
                                                            1
Error: 'r2' at (1) is not a member of the 'basetype' structure

I don't understand why these errors are produced since the compiler obviously recognizes the extended types exttype1 and exttype2. What's the correct way to access r1 and r2?

EDIT : By changing ary(i)%comp to this in each write(*,*) line, the code compiles normally. What difference does this modification make? How are these two NOT equivalent?

Xiasu Yang
  • 69
  • 5
  • Thanks a lot @francescalus! Changing `ary(i)%comp` to `this` does indeed solve my problem. I thought both would work since `this` is just a 'name tag' of `ary(i)%comp` – Xiasu Yang Mar 25 '20 at 16:12
  • I originally voted to close as a typo, but now you've expanded on the confusion around `this`, I've retracted and answered. Perhaps you can add that aspect to your question. – francescalus Mar 25 '20 at 16:31

1 Answers1

1

In the select type construct where one has

select type (this=>ary(i)%comp)

there are two things: the selector and the associate name. ary(i)%comp is the selector here and this is the associate name.

We know that an associate name is required in this case, because ary(i)%comp is not a name.

However, the associate name isn't just for convenience (like it may be in an associate construct): it has the fundamental required property that you need here. In the blocks governed by the type guards, the variable given by the associate name has declared type of the type guard; the selector retains the declared type as it had outside the construct.

Having the desired declared type allows us to access the components; simply having the dynamic type doesn't.

francescalus
  • 30,576
  • 16
  • 61
  • 96