Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`generic :: write(formatted)` subroutines in gfortran being called by other derived types

I am using several derived types. For debugging purposes, I would like to nicely print them on screen by using a generic :: write(formatted).

Here is an example program showing what I mean:

program main
  use :: test_mod
  implicit none

  type(test1) :: t1
  type(test2) :: t2

  t1 = test1(name="t1")
  t2 = test2(name="t2", t1)
  print *, 'Test1:', t1
  print *, 'Test2:', t2
end program

Here is the module:

module test_mod
  implicit none
  private
  public :: test1, test2

  type :: test1
    character(2) :: name
  contains
    procedure, private :: test1_writef
    generic :: write(formatted) => test1_writef
  end type test1

  type :: test2
    character(2) :: name
    type(test1) :: t1
  contains
    procedure, private :: test2_writef
    generic :: write(formatted) => test2_writef
  end type test2

contains

  subroutine test1_writef(self, unit, iotype, v_list, iostat, iomsg)
    class(test1), intent(in)    :: self      ! Object to write.
    integer, intent(in)         :: unit      ! Internal unit to write to.
    character(*), intent(in)    :: iotype    ! LISTDIRECTED or DTxxx
    integer, intent(in)         :: v_list(:) ! parameters from fmt spec.
    integer, intent(out)        :: iostat    ! non zero on error, etc.
    character(*), intent(inout) :: iomsg     ! define if iostat non zero.
    write (unit, "(a)", IOSTAT=iostat, IOMSG=iomsg) self%name
  end subroutine test1_writef

  subroutine test2_writef(self, unit, iotype, v_list, iostat, iomsg)
    class(test2), intent(in)    :: self      ! Object to write.
    integer, intent(in)         :: unit      ! Internal unit to write to.
    character(*), intent(in)    :: iotype    ! LISTDIRECTED or DTxxx
    integer, intent(in)         :: v_list(:) ! parameters from fmt spec.
    integer, intent(out)        :: iostat    ! non zero on error, etc.
    character(*), intent(inout) :: iomsg     ! define if iostat non zero.
    write (unit, "(a, ' <', a, '>')", IOSTAT=iostat, IOMSG=iomsg) self%name, self%t1
  end subroutine test2_writef

end module test_mod

Running this program I expected to obtain:

Test1: t1
Test2: t2 <t1>

But instead with gfortran I obtain:

Test1: t1
Test2: t2 <>

The "t1" string is not written on screen.

I am using this version of gfortran:

[egissi@shibax ~]$ gfortran --version
GNU Fortran (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

I know that I could just replace self%t1 with self%t1%name, but my types are much more complicated than that and I would better not repeat the same format in other derived types.

What am I missing? How can I obtain that behaviour?

like image 591
Emanuele Gissi Avatar asked Oct 16 '22 20:10

Emanuele Gissi


1 Answers

For a defined output procedure to be used it must be "selected" in some way. In the list-directed output

print *, 'Test1:', t1
print *, 'Test2:', t2

the procedures test1_writef and test2_writef are available for the effective items t1 and t2. They are therefore used.

However, for the child output

write (unit, "(a, ' <', a, '>')", IOSTAT=iostat, IOMSG=iomsg) self%name, self%t1

we now have an explicit format ("(a,' <',a,'>')"). Here the effective items self%name and self%t1 are edited explicitly as characters. To request the object self%t1 be processed according to test1_writef it is necessary to explicitly use a dt edit descriptor:

write (unit, "(a, ' <', dt, '>')", IOSTAT=iostat, IOMSG=iomsg) self%name, self%t1
like image 123
francescalus Avatar answered Oct 21 '22 04:10

francescalus