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

Problems when passing derived types to subroutine

Jan_M_
Beginner
727 Views

Hello,

i'm running in some trouble when trying to pass some derived types to subroutines for their allocation:

here some small example i created to explaining my problem:

the module containing the derived type:

module type
  implicit none
  private
  public :: mt, rk, ik, ck

  integer, parameter :: digits = 8
  integer, parameter :: decades = 9
  integer, parameter :: rk = selected_real_kind(digits)
  integer, parameter :: ik = selected_int_kind(decades)
  integer, parameter :: ck = selected_char_kind('default')

  type set
    character(kind=ck,len=80) :: name
    integer(ik), allocatable :: members(:)
  end type set

  type mytype
    type(set), allocatable :: nset(:)
  end type mytype
  type(mytype) :: mt
end module type

and the module containing the subroutines:

module allocating_sub 
  use type, only : ik, rk, ck
  implicit none
  private
  public :: allocating

  interface allocating
    module procedure allocating_real_1d, allocating_int_1d, allocating_char_1d
  end interface

contains

  subroutine allocating_real_1d(vec,length)
    implicit none
    real(rk), allocatable, intent(inout) :: vec(:)
    integer(ik), intent(in) :: length

    if(allocated(vec)) deallocate(vec)
    allocate(vec(length))
  end subroutine allocating_real_1d
  
  subroutine allocating_int_1d(vec,length)
    implicit none
    integer(ik), allocatable, intent(inout) :: vec(:)
    integer(ik), intent(in) :: length

    if(allocated(vec)) deallocate(vec)
    allocate(vec(length))
  end subroutine allocating_int_1d
  
  subroutine allocating_char_1d(vec,length)
    implicit none
    character(*), allocatable, intent(inout) :: vec(:)
    integer(ik), intent(in) :: length

    if(allocated(vec)) deallocate(vec)
    allocate(vec(length))
  end subroutine allocating_char_1d
  
end module allocating_sub

and finaly the main part:

program test
  use type, only : ik, rk, ck, mt
  use allocating_sub
  implicit none

  integer(ik), parameter :: nnsets = 4

  call allocating (mt%nsets(:),nnsets)
end program test

 

when i try to run this i get the following error:

error #6285: There is no matching specific subroutine for this generic subroutine call.   [ALLOCATING]  

Now i am asking myself how to write a subroutine allocating_xx which is able to handle such structures.

 

the following solution works but strongly impairs the readabilty of the main code if large type-structures are used:

if (allocated(mt%nset)) deallocate(mt%nset) ; allocate(mt%nset(nnsets))

 

Best regards,

Jan

 

0 Kudos
8 Replies
Steve_Lionel
Honored Contributor III
727 Views

The problem is this:

 call allocating (mt%nsets(:),nnsets)

Get rid of the (:) - it completely changes the meaning of what you're doing here. See here for more.

0 Kudos
Jan_M_
Beginner
727 Views

Hello Steve,

thank you for your fast reply.

I already tried this, but the error still remains.

This would work totally fine if mt%nset was the final / lowest "level" of the type mt.

I only get this error if "sublevels" like mt%nset%name exist and i try to allocate mt%nset(1:nnsets) via subroutine call.

small correction to the above code: mt%nsets has to be mt%nset

 

0 Kudos
Steve_Lionel
Honored Contributor III
727 Views

Ok. You did need to remove the (:) as the (:) makes the argument incompatible with the ALLOCATABLE attribute.

The more basic problem is that you are passing something of type SET where the generic has corresponding dummy arguments of type real, integer or character.  It's not clear to me what you want to do here - how do you want to decide what type to allocate?

There seems to be something missing here. Can you explain in more detail what you want to accomplish? If you want a component that can be of multiple types, you could make it CLASS(*) but then would have to explicitly specify the type when allocating.

0 Kudos
Jan_M_
Beginner
727 Views

Ok, i will try to make it more clear

Let's say i have a base type set. A set has a name set%name and consists of an unknown amount of members set%members

type set
  character(*) :: name
  integer(ik), allocatable :: members(:)
end type set

Further i have a database this database consits of a unknown (at least at that point) amount of sets

type database
  type(set), allocatable :: set(:)
  integer(ik) :: nsets
end type database

Then an external input-file is read. There the amount of sets (database%nsets) in the database can be evaluated. And now i want to asign this dimension to the database%set(1:database%nsets). This works totally fine using:

if (allocated(database%set)) deallocate(database%set) ; allocate(database%set(database%nsets))

But since the code has a lot of lines (plus i have to use this multiple times) and the name of the types and their derived types are pretty long i wanted to put this into a suibroutine to improve readability since i am the only one woring on this code, but not the only one using it.

0 Kudos
Steve_Lionel
Honored Contributor III
727 Views

What you describe here is easy, but I don't see how it relates to having integer, real and character allocating routines. You can have a single allocate routine that gets passed database%set and allocates it to the desired size.

0 Kudos
Jan_M_
Beginner
727 Views
I wanted total create a multi-purpose subroutine to be able to allocate types, reals, integers, and characters by calling the overloaded subroutine "allocating". But it seems like I complicated things way too much...
0 Kudos
FortranFan
Honored Contributor II
727 Views

Jan M. wrote:

.. it seems like I complicated things way too much...

@Jan M.,

With (re)allocate on assignment facility in the Fortran standard that is very convenient with intrinsic types as well as derived types whose components do not have attributes that might complicate matters (e.g., POINTERs) or subcomponents thereof, do you even need the overloaded "allocating" procedure?

https://software.intel.com/en-us/fortran-compiler-18.0-developer-guide-and-reference-standard-realloc-lhs

0 Kudos
Jan_M_
Beginner
727 Views

Hello FortranFan,

thank you very much, i was not aware of this compiler-option (i found out it was turned off).

You are right, considering this i don't need the overloaded subroutine.

 

0 Kudos
Reply