Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Beginner
22 Views

User defined derived-ype IO for extended type

Jump to solution
I'd like to add user defined derived-type IO for an extended type. However I got an error message "error #8638: The type/rank signature for arguments of this specific subroutine is identical to another specific subroutine that shares the same defined I/O." Anyone has idea how to do this? The test code is here. module mymod type :: mydata_t character(len=10) :: name contains procedure :: write_unfmt_mydata generic :: write(unformatted) => write_unfmt_mydata end type mydata_t type, extends(mydata_t) :: myint_t integer :: nn integer, pointer :: xx(:) contains procedure :: write_unfmt_myint !! How can I add an UDIO for an extended type? !! The following line causes compilation error generic :: write(unformatted) => write_unfmt_myint end type myint_t contains subroutine write_unfmt_mydata(dtv, unit, iostat, iomsg) class(mydata_t), intent(in) :: dtv integer, intent(in) :: unit integer, intent(out) :: iostat character(len=*), intent(inout) :: iomsg write(unit, iostat=iostat, iomsg=iomsg) dtv%name end subroutine write_unfmt_mydata subroutine write_unfmt_myint(dtv, unit, iostat, iomsg) class(myint_t), intent(in) :: dtv integer, intent(in) :: unit integer, intent(out) :: iostat character(len=*), intent(inout) :: iomsg write(unit, iostat=iostat, iomsg=iomsg) dtv%mydata_t write(unit, iostat=iostat, iomsg=iomsg) dtv%nn write(unit, iostat=iostat, iomsg=iomsg) dtv%xx(1:nn) end subroutine write_unfmt_myint end module mymod program test use mymod type(mydata_t) :: dd type(myint_t) :: ii dd = mydata_t( 'xyz' ) ii%name = 'abc' ii%nn = 100 allocate(ii%xx(ii%nn)) ii%xx = 5 open(10, file='test.dat', form='unformatted') write(10) dd write(10) ii end program test
0 Kudos

Accepted Solutions
Highlighted
Valued Contributor III
22 Views

Dong Zheng wrote:

I'd like to add user defined derived-type IO for an extended type. However I got an error message
"error #8638: The type/rank signature for arguments of this specific subroutine is identical to another specific subroutine that shares the same defined I/O." Anyone has idea how to do this? ..

With your design with the derived type and its extension type in the same module and thus any considerations of PRIVATE/PUBLIC attributes being moot, you need to effectively employ the "override" feature in standard Fortran to point the specific binding in the extension type to its own implementation.  The generic binding can be retained as-is.

   type, extends(mydata_t) :: myint_t
      integer :: nn
      integer, pointer :: xx(:)
   contains
      ! "override" write_unfmt_mydata with a specific procedure binding
      ! to myint_t
      procedure :: write_unfmt_mydata => write_unfmt_myint
   end type myint_t

 

View solution in original post

0 Kudos
6 Replies
Highlighted
Valued Contributor I
22 Views

Abstract interfaces?

0 Kudos
Highlighted
Valued Contributor III
23 Views

Dong Zheng wrote:

I'd like to add user defined derived-type IO for an extended type. However I got an error message
"error #8638: The type/rank signature for arguments of this specific subroutine is identical to another specific subroutine that shares the same defined I/O." Anyone has idea how to do this? ..

With your design with the derived type and its extension type in the same module and thus any considerations of PRIVATE/PUBLIC attributes being moot, you need to effectively employ the "override" feature in standard Fortran to point the specific binding in the extension type to its own implementation.  The generic binding can be retained as-is.

   type, extends(mydata_t) :: myint_t
      integer :: nn
      integer, pointer :: xx(:)
   contains
      ! "override" write_unfmt_mydata with a specific procedure binding
      ! to myint_t
      procedure :: write_unfmt_mydata => write_unfmt_myint
   end type myint_t

 

View solution in original post

0 Kudos
Highlighted
Beginner
22 Views

@FortranFan,

Thanks. This works.

 

0 Kudos
Highlighted
Valued Contributor III
22 Views

@Dong Zheng,

Please note if you wish to follow suggested good practices with object-oriented (OO) design that starts with "information hiding" but yet strive to have your Fortran derived types reflect and OO "class" in conjunction with Fortran standard facilities of having methods operate on a "class" and inherit and employ polymorphism in terms of Fortran type-bound procedures and their extension, then consider having each derived type in its own module, control information in terms of PRIVATE/PUBLIC attributes, adopt "names" of specific bindings via xx => yy option, etc. as shown below.  I don't extend the concept to data encapsulated by the derived type but the same principles apply.  Proceed carefully though because OO, like pointers, can give coders a long rope to tie themselves up in all kinds of knots if not handled carefully.

module mydata_m
   
   implicit none
   
   private
   
   type, public :: mydata_t
      character(len=10) :: name
   contains
      private
      procedure, pass(dtv) :: write_unfmt => write_unfmt_mydata
      generic, public :: write(unformatted) => write_unfmt
   end type mydata_t
   
contains

   subroutine write_unfmt_mydata(dtv, unit, iostat, iomsg)
   
      class(mydata_t), intent(in)     :: dtv
      integer, intent(in)             :: unit
      integer, intent(out)            :: iostat
      character(len=*), intent(inout) :: iomsg
      
      write(unit, iostat=iostat, iomsg=iomsg) dtv%name
      
   end subroutine write_unfmt_mydata
   
end module mydata_m

module myint_m

   use mydata_m, only : mydata_t
   
   implicit none
   
   private
   
   type, extends(mydata_t), public :: myint_t
      integer :: nn
      integer, pointer :: xx(:)
   contains
      private
      procedure, pass(dtv) :: write_unfmt => write_unfmt_myint
   end type myint_t
   
contains

   subroutine write_unfmt_myint(dtv, unit, iostat, iomsg)
   
      class(myint_t), intent(in)      :: dtv
      integer, intent(in)             :: unit
      integer, intent(out)            :: iostat
      character(len=*), intent(inout) :: iomsg
      
      write(unit, iostat=iostat, iomsg=iomsg) dtv%mydata_t
      write(unit, iostat=iostat, iomsg=iomsg) dtv%nn
      write(unit, iostat=iostat, iomsg=iomsg) dtv%xx(1:dtv%nn)
      
   end subroutine write_unfmt_myint
   
end module myint_m

program test

   use mydata_m, only : mydata_t
   use myint_m, only : myint_t
   
   implicit none

   type(mydata_t) :: dd
   type(myint_t) :: ii
   dd = mydata_t( 'xyz' )
   ii%name = 'abc'
   ii%nn = 100
   allocate(ii%xx(ii%nn))
   ii%xx = 5

   open(10, file='test.dat', form='unformatted')
   write(10) dd
   write(10) ii
   
end program test

 

0 Kudos
Highlighted
Beginner
22 Views
@FortranFan Thanks for the advice and I totally agree with you. However, when I test the code you posted above. It compiled with no problem but did not work as expected. I add a print statement in both "write_unfmt_mydata" and "write_unfmt_myint" respectively. It shows that "write_unfmt_myint" is not used. When I rearrange your code (with out change) in to one module, then it works fine. I cannot figure out why. Could you have a look? The test code is attached.
0 Kudos
Highlighted
Valued Contributor III
22 Views

Dong Zheng wrote:

.. when I test the code you posted above. It compiled with no problem but did not work as expected. I add a print statement in both "write_unfmt_mydata" and "write_unfmt_myint" respectively. It shows that "write_unfmt_myint" is not used. ..

My hunch at present is this is a compiler bug in Intel Fortran.  Note the output with gfortran is as I currently expect - see below.  I'll check the standard further on this.

C:\Temp>type p.f90
module mydata_m

   implicit none

   private

   type, public :: mydata_t
      character(len=10) :: name
   contains
      private
      procedure, pass(dtv) :: write_unfmt => write_unfmt_mydata
      generic, public :: write(unformatted) => write_unfmt
   end type mydata_t

contains

   subroutine write_unfmt_mydata(dtv, unit, iostat, iomsg)

      class(mydata_t), intent(in)     :: dtv
      integer, intent(in)             :: unit
      integer, intent(out)            :: iostat
      character(len=*), intent(inout) :: iomsg

      print *, 'in mydata'
      write(unit, iostat=iostat, iomsg=iomsg) dtv%name

   end subroutine write_unfmt_mydata

end module mydata_m

module myint_m

   use mydata_m, only : mydata_t

   implicit none

   private

   type, extends(mydata_t), public :: myint_t
      integer :: nn
      integer, pointer :: xx(:)
   contains
      private
      procedure, pass(dtv) :: write_unfmt => write_unfmt_myint
   end type myint_t

contains

   subroutine write_unfmt_myint(dtv, unit, iostat, iomsg)

      class(myint_t), intent(in)      :: dtv
      integer, intent(in)             :: unit
      integer, intent(out)            :: iostat
      character(len=*), intent(inout) :: iomsg

      print *, 'in myint'
      write(unit, iostat=iostat, iomsg=iomsg) dtv%mydata_t
      write(unit, iostat=iostat, iomsg=iomsg) dtv%nn
      write(unit, iostat=iostat, iomsg=iomsg) dtv%xx(1:dtv%nn)

   end subroutine write_unfmt_myint

end module myint_m

program test

   use, intrinsic :: iso_fortran_env, only : compiler_version
   use mydata_m, only : mydata_t
   use myint_m, only : myint_t

   implicit none

   type(mydata_t) :: dd
   type(myint_t) :: ii

   print *, "Compiler Version: ", compiler_version()
   dd = mydata_t( 'xyz' )
   ii%name = 'abc'
   ii%nn = 100
   allocate(ii%xx(ii%nn))
   ii%xx = 5

   open(10, file='test.dat', form='unformatted')
   write(10) dd
   write(10) ii

end program test

C:\Temp>gfortran -Wall -std=f2018 p.f90 -o p.exe

C:\Temp>p.exe
 Compiler Version: GCC version 10.0.0 20190512 (experimental)
 in mydata
 in myint
 in mydata

C:\Temp>

 

0 Kudos