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?
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With