Question

I am trying to find a way to pass derived-type objects with allocatable components to Fortran procedures, without the procedures knowing the type definition. To understand why I want to do this, some info on the background may be useful.

Consider a generic procedure that contains a sparse-matrix - vector multiplication, like a Lanczos diagonalization routine. The procedure itself does not use the matrix, only the vector. The only thing the procedure needs to do with the matrix is to pass it, along with the vector, to a matrix-vector multiplication routine. The sparse matrix has to be a derived-type variable with allocatable components.

The way I see it, the procedure does not need to know the data type of the sparse matrix. It just needs to pass it to the matrix-vector multiplication routine, which will then decode it appropriately. What I tried to do was to use the TRANSFER intrinsic function to cast the derived-type variable into an allocatable array of bytes, and then transfer it back to the initial derived-type variable. This unfortunately does not work with derived-type variables with allocatable components, see the following two links: Link 1, Link 2

My question is therefore the following, as stated above: is there a reasonable way* to pass derived-type objects with allocatable components to Fortran procedures, without the procedures knowing the type definition?

*Note: I know that I could use customized internal formatted writes to store a derived-type variable into an intrinsic-type array, e.g. a character array. This seems to me extremely weird, but maybe I'm wrong?

EDIT :: as Vladimir F says below, the behaviour when invoking TRANSFER for derived types with allocatable components is non-standard. Yet, I found out that, surprisingly, this works with the latest version of the PGI compiler. Here is a test program:

module Increments

  TYPE :: structure
    real s
    integer q
    real, allocatable :: flt1d(:)
  END TYPE structure

contains

  subroutine IncrementAndPrintReal(data)
    character(len=1) :: data(:)
    real             :: r
    r = transfer(data, r)
    r = r + 1.0 
    print *,r
    data = transfer(r, data)
  end subroutine

  subroutine IncrementAndPrintInteger(data)
    character(len=1) :: data(:) 
    integer          :: i    
    i = transfer(data, i)
    i = i + 1 
    print *,i
    data = transfer(i, data)
  end subroutine

  subroutine IncrementTenTimes(incrFunc, data)
    character(len=1) :: data(:) 
    integer :: i
    interface
      subroutine incrFunc(data)
        character(len=1) :: data(:) 
      end subroutine
    end interface
    do i = 1, 10 
      call incrFunc(data)
    enddo   
  end subroutine

  subroutine IncrementAndPrintStructure(data)
    character(len=1) :: data(:)
    type(structure) :: t0
    t0 = transfer(data, t0)
    print *, t0%flt1d
    t0%flt1d = t0%flt1d(1) + 1
    print*
    data = transfer(t0, data)
  end subroutine

end module

program main
  use Increments
  character(len=1), allocatable :: data(:) 
  integer                       :: lengthData
  real                          :: r = 5.0 
  integer                       :: i = 10
  type(structure)               :: t

  t%s = 1
  t%q = 2
  allocate(t%flt1d(11))
  t%flt1d = 3

  lengthData = size(transfer(r, data))
  allocate(data(lengthData))
  data = transfer(r, data)
  call IncrementTenTimes(IncrementAndPrintReal, data)
  deallocate(data)

  lengthData = size(transfer(i, data))
  allocate(data(lengthData))
  data = transfer(i, data)
  call IncrementTenTimes(IncrementAndPrintInteger, data)
  deallocate(data)

  lengthData = size(transfer(t, data))
  allocate(data(lengthData))
  data = transfer(t, data)
  call IncrementTenTimes(IncrementAndPrintStructure, data)
  deallocate(data)

end program

And here are the results for different compilers:

ifort (v11.1 and v12.1.5):
==============


   6.000000    
   7.000000    
   8.000000    
   9.000000    
   10.00000    
   11.00000    
   12.00000    
   13.00000    
   14.00000    
   15.00000    
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
   3.000000       3.000000       3.000000       3.000000       3.000000    
   3.000000       3.000000       3.000000       3.000000       3.000000    
   3.000000    

  0.0000000E+00  0.0000000E+00   4.000000       4.000000       4.000000    
   4.000000       4.000000       4.000000       4.000000       4.000000    
   4.000000    

  0.0000000E+00  0.0000000E+00   1.000000       1.000000       1.000000    
   1.000000       1.000000       1.000000       1.000000       1.000000    
   1.000000    

  0.0000000E+00  0.0000000E+00   1.000000       1.000000       1.000000    
   1.000000       1.000000       1.000000       1.000000       1.000000    
   1.000000    

  0.0000000E+00  0.0000000E+00   1.000000       1.000000       1.000000    
   1.000000       1.000000       1.000000       1.000000       1.000000    
   1.000000    

  0.0000000E+00  0.0000000E+00   1.000000       1.000000       1.000000    
   1.000000       1.000000       1.000000       1.000000       1.000000    
   1.000000    

  0.0000000E+00  0.0000000E+00   1.000000       1.000000       1.000000    
   1.000000       1.000000       1.000000       1.000000       1.000000    
   1.000000    

  0.0000000E+00  0.0000000E+00   1.000000       1.000000       1.000000    
   1.000000       1.000000       1.000000       1.000000       1.000000    
   1.000000    

  0.0000000E+00  0.0000000E+00   1.000000       1.000000       1.000000    
   1.000000       1.000000       1.000000       1.000000       1.000000    
   1.000000    

  0.0000000E+00  0.0000000E+00   1.000000       1.000000       1.000000    
   1.000000       1.000000       1.000000       1.000000       1.000000    
   1.000000    



gfortran (gcc version 4.4.3):
=============================


   6.0000000    
   7.0000000    
   8.0000000    
   9.0000000    
   10.000000    
   11.000000    
   12.000000    
   13.000000    
   14.000000    
   15.000000    
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
   3.0000000       3.0000000       3.0000000       3.0000000       3.0000000       3.0000000       3.0000000       3.0000000       3.0000000       3.0000000       3.0000000    

  1.82795013E-38   0.0000000       4.0000000       4.0000000       4.0000000       4.0000000      1.54142831E-44  1.12103877E-44  2.80259693E-45   4.0000000       4.0000000    

*** glibc detected *** ./tr: double free or corruption (fasttop): 0x0000000000c70b20 ***
======= Backtrace: =========
/lib/libc.so.6(+0x77806)[0x7f9fb0e59806]
/lib/libc.so.6(cfree+0x73)[0x7f9fb0e600d3]
./tr[0x4010af]
./tr[0x401175]
./tr[0x40262e]
./tr[0x4026ea]
/lib/libc.so.6(__libc_start_main+0xfd)[0x7f9fb0e00c4d]
./tr[0x400a59]
======= Memory map: ========
00400000-00403000 r-xp 00000000 00:16 123                                /home/stefanos/Documents/dig/progs/other/transfer/tr
00602000-00603000 r--p 00002000 00:16 123                                /home/stefanos/Documents/dig/progs/other/transfer/tr
00603000-00604000 rw-p 00003000 00:16 123                                /home/stefanos/Documents/dig/progs/other/transfer/tr
00c70000-00c91000 rw-p 00000000 00:00 0                                  [heap]
7f9fac000000-7f9fac021000 rw-p 00000000 00:00 0 
7f9fac021000-7f9fb0000000 ---p 00000000 00:00 0 
7f9fb0de2000-7f9fb0f5c000 r-xp 00000000 08:01 5512795                    /lib/libc-2.11.1.so
7f9fb0f5c000-7f9fb115b000 ---p 0017a000 08:01 5512795                    /lib/libc-2.11.1.so
7f9fb115b000-7f9fb115f000 r--p 00179000 08:01 5512795                    /lib/libc-2.11.1.so
7f9fb115f000-7f9fb1160000 rw-p 0017d000 08:01 5512795                    /lib/libc-2.11.1.so
7f9fb1160000-7f9fb1165000 rw-p 00000000 00:00 0 
7f9fb1165000-7f9fb117b000 r-xp 00000000 08:01 5505258                    /lib/libgcc_s.so.1
7f9fb117b000-7f9fb137a000 ---p 00016000 08:01 5505258                    /lib/libgcc_s.so.1
7f9fb137a000-7f9fb137b000 r--p 00015000 08:01 5505258                    /lib/libgcc_s.so.1
7f9fb137b000-7f9fb137c000 rw-p 00016000 08:01 5505258                    /lib/libgcc_s.so.1
7f9fb137c000-7f9fb13fe000 r-xp 00000000 08:01 5505028                    /lib/libm-2.11.1.so
7f9fb13fe000-7f9fb15fd000 ---p 00082000 08:01 5505028                    /lib/libm-2.11.1.so
7f9fb15fd000-7f9fb15fe000 r--p 00081000 08:01 5505028                    /lib/libm-2.11.1.so
7f9fb15fe000-7f9fb15ff000 rw-p 00082000 08:01 5505028                    /lib/libm-2.11.1.so
7f9fb15ff000-7f9fb16ea000 r-xp 00000000 08:01 787983                     /usr/lib/libgfortran.so.3.0.0
7f9fb16ea000-7f9fb18e9000 ---p 000eb000 08:01 787983                     /usr/lib/libgfortran.so.3.0.0
7f9fb18e9000-7f9fb18ea000 r--p 000ea000 08:01 787983                     /usr/lib/libgfortran.so.3.0.0
7f9fb18ea000-7f9fb18eb000 rw-p 000eb000 08:01 787983                     /usr/lib/libgfortran.so.3.0.0
7f9fb18eb000-7f9fb18ec000 rw-p 00000000 00:00 0 
7f9fb18ec000-7f9fb190c000 r-xp 00000000 08:01 5512780                    /lib/ld-2.11.1.so
7f9fb1ad9000-7f9fb1add000 rw-p 00000000 00:00 0 
7f9fb1b09000-7f9fb1b0b000 rw-p 00000000 00:00 0 
7f9fb1b0b000-7f9fb1b0c000 r--p 0001f000 08:01 5512780                    /lib/ld-2.11.1.so
7f9fb1b0c000-7f9fb1b0d000 rw-p 00020000 08:01 5512780                    /lib/ld-2.11.1.so
7f9fb1b0d000-7f9fb1b0e000 rw-p 00000000 00:00 0 
7fff5e340000-7fff5e356000 rw-p 00000000 00:00 0                          [stack]
7fff5e396000-7fff5e397000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted



pgfortran (v12.5):
==================


    6.000000    
    7.000000    
    8.000000    
    9.000000    
    10.00000    
    11.00000    
    12.00000    
    13.00000    
    14.00000    
    15.00000    
           11
           12
           13
           14
           15
           16
           17
           18
           19
           20
    3.000000        3.000000        3.000000        3.000000     
    3.000000        3.000000        3.000000        3.000000     
    3.000000        3.000000        3.000000    

    4.000000        4.000000        4.000000        4.000000     
    4.000000        4.000000        4.000000        4.000000     
    4.000000        4.000000        4.000000    

    5.000000        5.000000        5.000000        5.000000     
    5.000000        5.000000        5.000000        5.000000     
    5.000000        5.000000        5.000000    

    6.000000        6.000000        6.000000        6.000000     
    6.000000        6.000000        6.000000        6.000000     
    6.000000        6.000000        6.000000    

    7.000000        7.000000        7.000000        7.000000     
    7.000000        7.000000        7.000000        7.000000     
    7.000000        7.000000        7.000000    

    8.000000        8.000000        8.000000        8.000000     
    8.000000        8.000000        8.000000        8.000000     
    8.000000        8.000000        8.000000    

    9.000000        9.000000        9.000000        9.000000     
    9.000000        9.000000        9.000000        9.000000     
    9.000000        9.000000        9.000000    

    10.00000        10.00000        10.00000        10.00000     
    10.00000        10.00000        10.00000        10.00000     
    10.00000        10.00000        10.00000    

    11.00000        11.00000        11.00000        11.00000     
    11.00000        11.00000        11.00000        11.00000     
    11.00000        11.00000        11.00000    

    12.00000        12.00000        12.00000        12.00000     
    12.00000        12.00000        12.00000        12.00000     
    12.00000        12.00000        12.00000    
Was it helpful?

Solution 2

By asking this question in the PGI forum, I learned about allocatable unlimited polymorphic objects CLASS(*), ALLOCATABLE (thanks mkcolg). This seems to be a better way to pass derived-type data around, since it allows for proper type checking when the data reaches the relevant module / procedure. Examples can be found in the PGInsider article Object-Oriented Programming in Fortran 2003 Part 2: Data Polymorphism.

OTHER TIPS

You can not expect any standard behauvior for allocatable components. In no case they are stored inside the d. type structure and also they are not simple adresses. It is unclear to me without any code, if you are accessing the descriptor or the pointee. Anyway, for reliable generic programming you should probably use standard generic interfaces to multiple procedures and maybe using a common body for them using INCLUDE.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top