Error: The part-name to the right of a part-ref with nonzero rank has the ALLOCATABLE attribute

2.2k views Asked by At

I would like to access the the elements of an array in a an arrayed derived type using the subroutine sum_real. That is: sum over first entry in the weight for all people.

type my_type
   real, dimension(:), allocatable :: weight
   real :: total_weight
end type my_type

type (my_type), dimension (:), allocatable :: people
type (my_type) :: answer

allocate (people (2))
allocate (people (1)%weight(2))
allocate (people (2)%weight(2))

people (1) % weight(1) = 1
people (2) % weight(1) = 1
people (1) % weight(2) = 3
people (2) % weight(2) = 3

call sum_real ( people (:) % weight(1), answer % total_weight )

What I want to do is similar to the answer found in Array of derived type: select entry, except for the fact that I have an allocated array in an arrayed derived type instead of an single element.

But, I get a compiler error:

error #7828: The part-name to the right of a part-ref with nonzero rank has the ALLOCATABLE attribute (6.1.2).   [WEIGHT]
2

There are 2 answers

0
Vladimir F Героям слава On BEST ANSWER

What you try is not possible if your component is allocatable. The reference (6.1.2) is actually a reference to the official standard documents, which prohibits this.

The reason is simple, the allocatable components (scalar or arrays) are stored in a different part of memory than the derived type itself. Therefore if you write

sum(people%total_weight)

or

people%total_weight = 0

it is no problem, total_weight is not allocatable, it is stored within the derived type and the compiler just goes in a simple loop and sets one field after another to zero. You can know the address of each %totalweight beforehand.

On the other hand

sum(people%weight)

or

people%weight = 0

each %weight is stored elsewhere and you don't have any simple formula to compute where is each %weight(i).

The solution is either, to fix the size of the array, if possible

real, dimension(2) :: weight

or use a do loop

s = 0
do i = 1, size(people)
  S = S + sum(people(i)%weight)
end do
0
IanH On

If you have a F2003 compiler, and the bounds of the component array are the same for a particular parent array object, a third approach to the size specified by constant expression/use a do loop methods specified by VladimirF is to parameterize the type.

type my_type(n)        ! This type has one parameter - n
  integer, len :: n    ! The parameter n is a length parameter.
  real :: weight(n)    ! This component depends on that parameter.
end type my_type

type (my_type(:)), dimension(:), allocatable :: people

! This integer is the size of the people component.  Because 
! people is allocatable it can be determined at runtime.
number_of_people = 2

! This integer is the size of the weight component that we want 
! in the array people.  Other arrays and scalars of type 
! my_type can have different sizes for that component.  
! Because people is allocatable this can be determined at 
! runtime.
number_of_weights = 2

allocate( my_type(number_of_weights) :: people(number_of_people) )

! Define people%weight here.
people(1)%weight(1) = 1
...

! Using sum intrinsic for the sake of example
do i = 1, people%n
  ! The argument to sum is an array section.
  print *, sum(people%weight(i))
  !                 ^        ^ Reference to an element of a component
  !                 | Reference to the entire people array
end do

Every element in an array of parameterized type has the same type parameters, hence every weight component in people has the same bounds, hence references such as people%weight become "regular".

Code using this approach (or the constant component size specification approach) still has to follow the restriction for component references that only one part of the reference can have non-zero rank (you can't work with people%weight as a whole as both people and the weight component have rank one).

In the allocatable component case some components in some elements might not be allocated and where they are allocated the component might have different bounds, making a "regular" reference to the data in the component across the elements of the array conceptually difficult.