Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29256 Discussions

are arrays of components of derived type legal in F-95?

forall
Beginner
738 Views
A few questions re derived types:

1) Is it legal to create arrays using components of derived types, eg,
arr(:)=var(:)%comp
assuming arr and comp are of the same type and their dimensions match.

2) Can they be used as targets of pointer association, eg
p=>var(:)%comp

3) Can they be passed to subroutines expecting array arguments, eg,
call sub(arr=var(:)%comp)

It appears that both IVF and CVF function correctly in simple cases (eg, see below), but I have a large program where this could be a problem and so wanted to check that these usages (especially 2 and 3) are indeed legal.

thanks in advance,
dmitri

!***************************
module m
implicit none
type t
real::r
endtype t
contains
!---
subroutine test(argR)
real,intent(in)::argR(:)
integer::i
do i=1,size(argR)
write(*,*)argR(i)
enddo
endsubroutine test
!---
endmodule m
!*****************************
subroutine sample_subroutine()
use m,only:t,test
implicit none
integer,parameter::n=2
type(t),target::var(n)
real,pointer::p(:)
! does 'var(:)%r' constitute a valid array?
var(:)%r=(/1.0,2.0/) ! is this assignment valid?
p=>var(:)%r ! is this pointer statement legal?
call test(argR=var(:)%r) ! is this call legal?
call test(argR=p)
endsubroutine sample_subroutine
!******************************
0 Kudos
5 Replies
Steven_L_Intel1
Employee
738 Views
Yes to all three, but for the pointer assignment, var has to have the TARGET attribute.

I would recommend not using the (:) in expressions as it can sometimes inhibit optimizations, but I understand if you want to use it to make clear it's an array.
0 Kudos
jimdempseyatthecove
Honored Contributor III
738 Views

Your example is inadequate for testing. To make a better test try

type t
sequence
real(8)::r
integer(4) :: i
endtype t

This way the array of t's is not equivilent to the array of t%r (i.e. the group of r's are not in adjecent memory. And the additional member of t is not a multiple of the size of r.

It is unknown to me as to if the compiler creates a temporary array or if it creates a descriptor with stride when passing var(:)%r as an argument Looking at the dissassembly window would tell you which method was used. Creating an array descriptor with stride would be useful when calling a Fortran subroutine. To get the descriptor passed you would have to declare an interface with the dummy argument declared with (:). For calling a C/C++ you might want the compiler to construct a temporary array as C++ subroutines tend to not examine the Fortran descriptor.

Jim Dempsey

0 Kudos
forall
Beginner
738 Views
Yes, it seems having more complex (misaligned) derived types triggers a bug when also requiring temp copies for passign arguments.

I tracked down my problem to the following reduced case, which crushes with stack overflow (but doesnt work properly otherwise either). Strangely enough in a more complex code this results in the string becoming blank, rather than causing stack-problems when passing it.

Now I am wondering whether using arrays of components of derived types is a good idea even if it is legal, since it seems to require the creation of temp storage whenever the derived type contains components of different memory lengths (in which case it would be impossible to create a compact descriptor with strides?) - is this a fair statement?

!******************************************************************
module m
implicit none
contains
!----------------------------------------------------
subroutine sub1(vname)
implicit none
! dummies
character(*),intent(in)::vname(:)
call sub2(vname,n=size(vname))
endsubroutine sub1
!----------------------------------------------------
subroutine sub2(item,n)
implicit none
integer,intent(in) :: n
character(*),intent(in) :: item(n) ! this line crashes the code (explicit-shape array)
!character(*),intent(in) :: item(:) ! this line works
write(10,'(a)')"'"//item//"'" ! this statement fails
endsubroutine sub2
!----------------------------------------------------
endmodule m
!*****************************************************************
subroutine sample_subroutine()
use m
implicit none
type var1_type
character(10)::name
real::v ! removing this component makes the code work always (aligned type)
endtype var1_type
integer,parameter::n=2
character(10)::vname(n)
type(var1_type)::var(n)
vname=(/"x1","x2"/)
var(:)%name=vname
call sub1(vname=vname) ! this works fine
call sub1(vname=var%name) ! this causes stack-overflow
endsubroutine sample_subroutine
!******************************************************************

0 Kudos
Steven_L_Intel1
Employee
738 Views
I don't understand your comment about strides - a component is always at a fixed offset from the beginning of the structure. That said, I would not be astonished if you always got a copy made when passing a component of an array of derived type.

Please report the bug to Intel Premier Support.
0 Kudos
jimdempseyatthecove
Honored Contributor III
738 Views

Steve,

>> I don't understand your comment about strides

The strides may or may not work, depending on how strides are internallyimplemented (number of items or number of bytes)

Consider

type t
sequence
real(8)::r
integer(4) :: i
endtype t
type(t) :: Tarray(100)

Tarray(1) would start a memory block of

real(8)
integer(4)
real(8)
integer(4)
real(8)
integer(4)
... 97 more times

In the above, each element of the array is 12 bytes (with external representation of stride implicitly being 1 element)

If the internal representation of Stride is in bytes then each 8-byte real would be positioned at 12-byte intervals. Although the 12 byte stride cannot be specified at the source code level, it can very well be specified in the descriptor. Therefore, a descriptor could be constructed for Tarray(:)%r and passed to a subrouting taking real(8) :: r(:) without requiring a copy to/from temp array.

As an alternate technique, the element size could be specified as being 12 bytes (and stride of 1 element).

r need not be at the base of the structure since the base address of the 1st r can be used in lieu of the base address of the first t.

Does this make sense to you?

Jim Dempsey

0 Kudos
Reply