User defined derived-ype IO for extended type

User defined derived-ype IO for extended type

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

publicaciones de 7 / 0 nuevos
Último envío
Para obtener más información sobre las optimizaciones del compilador, consulte el aviso sobre la optimización.

Abstract interfaces?

Best Reply

Quote:

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

 

@FortranFan,

Thanks. This works.

 

@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

 

@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.

Adjuntos: 

AdjuntoTamaño
Descargarapplication/x-tar multi_mod.tar10 KB

Cita:

Dong Zheng escribió:

.. 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>

 

Deje un comentario

Por favor inicie sesión para agregar un comentario. ¿No es socio? Únase ya