Reputation: 1972
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
Reputation: 60008
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
use the parametric list within the same library
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
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:
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
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