I am having trouble writing an allocatable array nested in a derived type using namelists. A minimal example is shown below. How can I modify the program to have the allocatable array inside the derived type work as though it were not nested?
program test
implicit none
type struct_foo
integer, allocatable :: nested_bar(:)
end type struct_foo
integer, allocatable :: bar(:)
type(struct_foo) :: foo
! namelist / list / foo, bar
namelist / list / bar
allocate(bar(5))
bar = [1:5]
allocate(foo%nested_bar(5))
foo%nested_bar=[1:5]
write(*,list)
end program test
With the foo commented out of the namelist, it works just fine, producing the output:
&LIST
BAR = 1, 2, 3, 4, 5
/
With foo included, the program fails to compile:
>> ifort -traceback test_1.f90 -o test && ./test
test_1.f90(20): error #5498: Allocatable or pointer derived-type fields require a user-defined I/O procedure.
write(*,list)
--------^
compilation aborted for test_1.f90 (code 1)
As the error message states, you need to provide a user defined derived type I/O (UDDTIO) procedure. This is required for input/output of any object with an allocatable or pointer component.
How the object of derived type is formatted in the file is completely under the control of the UDDTIO procedure.
An example, using a very simple output format, is below. Typically a UDDTIO procedure implementing namelist output would use an output format that was consistent with the other aspects of namelist output and typically there would also be a corresponding UDDTIO procedure that was then able to read the formatted results back in.
module foo_mod
implicit none
type struct_foo
integer, allocatable :: nested_bar(:)
contains
procedure, private :: write_formatted
generic :: write(formatted) => write_formatted
end type struct_foo
contains
subroutine write_formatted(dtv, unit, iotype, v_list, iostat, iomsg)
class(struct_foo), intent(in) :: dtv
integer, intent(in) :: unit
character(*), intent(in) :: iotype
integer, intent(in) :: v_list(:)
integer, intent(out) :: iostat
character(*), intent(inout) :: iomsg
integer :: i
if (allocated(dtv%nested_bar)) then
write (unit, "(l1,i10,i10)", iostat=iostat, iomsg=iomsg) &
.true., &
lbound(dtv%nested_bar, 1), &
ubound(dtv%nested_bar, 1)
if (iostat /= 0) return
do i = 1, size(dtv%nested_bar)
write (unit, "(i10)", iostat=iostat, iomsg=iomsg) &
dtv%nested_bar(i)
if (iostat /= 0) return
end do
write (unit, "(/)", iostat=iostat, iomsg=iomsg)
else
write (unit, "(l1,/)", iostat=iostat, iomsg=iomsg) .false.
end if
end subroutine write_formatted
end module foo_mod
program test
use foo_mod
implicit none
integer, allocatable :: bar(:)
type(struct_foo) :: foo
namelist / list / foo, bar
allocate(bar(5))
bar = [1:5]
allocate(foo%nested_bar(5))
foo%nested_bar=[1:5]
write (*,list)
end program test
Use of UDDTIO obviously requires a compiler that implements this Fortran 2003 language feature.