jvriesem
jvriesem

Reputation: 1972

Intrinsic Assignment and Polymorphism in Fortran 2003

I tried adding a procedure to this module, written by @VladimirF, that implements a generic linked list in Fortran 2003. I wanted to be able to output the contents of the list as an array for convenience, so I added the following procedure to a lists module in a file called lists.f90:

  subroutine list_as_array(self, arrayOut)
    class(list),intent(inout) :: self
    class(*),dimension(1:self%length),intent(out) :: arrayOut
    integer :: i
    type(list_node), pointer :: nodeIter
    nodeIter = self%first
    do i = 1,self%length
      arrayOut(i) = nodeIter%item  ! <---ERROR here
      if (i<self%length) then
        nodeIter = nodeIter%next
      end if
    end do
  end subroutine list_as_array

ifort 18.0.0 gives the following error:

lists.f90(324): error #8304: In an intrinsic assignment statement, variable shall not be a non-allocatable polymorphic.   [ARRAYOUT]
      arrayOut(i) = nodeIter%item
------^

I'm new to polymorphism in F2003+, so I do not understand the error message or its context. What's wrong, and how can it be fixed?

Upvotes: 3

Views: 1188

Answers (3)

I think other answers describe the problem well. One cannot assign to a polymorphic non-allocatable variable. And an array element is never allocatable.

I have thought about how to do such a thing, but I did not come up with a satisfactory solution how create such a function generically within the library. The main problem is that there is no type guard that would just check that the dynamic types of two entities are the same. You have to specify the actual type in SELECT TYPE.

As a user of the library, once you know that all elements are of the same type, you have two possibilities

  1. use the parametric list within the same library

  2. create your own function for each type that can appear in the array. Not in the library but in your own code. You must promise that all elements are of that type.

    subroutine integer_list_as_array(self, arrayOut)
      class(list),intent(inout) :: self
      integer,dimension(1:self%length),intent(out) :: arrayOut
      ...
    end subroutine integer_list_as_array
    

If anyone knows a trick to do that generically and just assume that all elements are of the same type, but without specifying the type, I would like to know that.

Upvotes: 2

francescalus
francescalus

Reputation: 32366

First, about the error message. In the absence of some defined assignment, the statement

arrayOut(i) = nodeIter%item

is an intrinsic assignment statement.

Fortran 2008 (not Fortran 2003) allows the variable on the left-hand side of this statement to be polymorphic. arrayOut(i) here is (unlimited) polymorphic. However, in allowing assignment to a polymorphic variable there is a restriction (F2008, 7.2.1.1 (1)):

if the variable is polymorphic it shall be allocatable and not a coarray

The compiler in this case is complaining because arrayOut(i) is not allocatable. However, even making arrayOut allocatable does not help: arrayOut(i) is an element of the array and will never be allocatable.

What you want to do simply here, cannot be done. This should be clear from the fact that in assigning to an array element you aren't guaranteeing that each element of the array is exactly the same type as the others. This is a requirement of a Fortran array, even a polymorphic one.

As to how you can do what you want, there are a couple of approaches:

  • convince the compiler that all elements will be of the same type;
  • use an array container.

This latter, like

type stuff
  class(*), allocatable :: item
end type stuff
type(stuff) arrayOut(length)

has come up in other contexts in questions and answer here.

For the "convincing", you'll need to make the left-hand side non-polymorphic.

Upvotes: 3

Steve Lionel
Steve Lionel

Reputation: 7267

The error message means what it says. The Fortran 2008 standard, describing the intrinsic assignment statement, says: "if the variable is polymorphic it shall be allocatable and not a coarray" arrayOut is CLASS(*), which makes in polymorphic. Only allocatable polymorphics can be assigned to.

As to "how to fix it", that would need some more context.

Upvotes: 5

Related Questions