classiofortranpolymorphismfortran2008

Fortran 2008 - user defined I/O procedure for CLASS(*)


I'm trying to make a type, which would serve as a wrapper for an arbitrary other types, so I could make a heterogeneous array, as it's advised in Heterogeneous array of Fortran classes and Creating heterogeneous arrays in Fortran.

So, I've tried to implement it like this:

module m
implicit none

type :: container
    class(*), pointer, public :: item
end type container
end module m

program mwe 
use m

implicit none

type(container) :: cont
integer, target :: i

i = 5 
cont = container(i)

write(*,*) cont%item

end program mwe 

Now I'm getting error

test4.f90(20): error #5513: A polymorphic I/O list item requires a user-defined derived-type input/output procedure.
    write(*,*) cont%item
----^
compilation aborted for test4.f90 (code 1)

So I tried to implement I/O like this:

module m
    implicit none

    type :: container
        class(*), pointer, public :: item
    contains
        procedure :: write_sample => write_container_sample_impl
        procedure :: read_sample  => read_container_sample_impl

        generic   :: write(unformatted) => write_sample
        generic   :: read(unformatted) => read_sample
    end type container

contains

    subroutine write_container_sample_impl(this, unit, iostat, iomsg)
        class(container), intent(in)    :: this
        integer, intent(in)         :: unit
        integer, intent(out)        :: iostat
        character(*), intent(inout) :: iomsg

        write(unit, iostat=iostat, iomsg=iomsg) this%item
    end subroutine write_container_sample_impl

    subroutine read_container_sample_impl(this, unit, iostat, iomsg)
        class(container), intent(inout) :: this
        integer, intent(in)         :: unit
        integer, intent(out)        :: iostat
        character(*), intent(inout) :: iomsg

        read(unit, iostat=iostat, iomsg=iomsg) this%item
    end subroutine read_container_sample_impl

end module m

program mwe 
    use m

    implicit none

    type(container) :: cont
    integer, target :: i

    i = 5 
    cont = container(i)

    write(*,*) cont%item

end program mwe 

But the same error occurs even in my new methods:

test4.f90(22): error #5513: A polymorphic I/O list item requires a user-defined derived-type input/output procedure.
        write(unit, iostat=iostat, iomsg=iomsg) this%item
--------^
test4.f90(31): error #5513: A polymorphic I/O list item requires a user-defined derived-type input/output procedure.
        read(unit, iostat=iostat, iomsg=iomsg) this%item
--------^
test4.f90(47): error #5513: A polymorphic I/O list item requires a user-defined derived-type input/output procedure.
    write(*,*) cont%item
----^

So, I have two questions:

  1. How should I implement it correctly?
  2. Is it better/easier to declare item variable as a pointer or as an allocatable variable?

Solution

  • Working with unlimited polymorphic entities is demanding.

    Adding the defined input/output procedures for the container type doesn't solve your problem because the problem isn't with the container itself. Instead it is the component of the container which is polymorphic and requiring the defined I/O procedure.

    Unfortunately though, because that component is unlimited polymorphic it isn't possible to define such a procedure.1

    Further, your defined I/O procedures for the container type won't actually be used. You have defined procedures only for unformatted input and output, but write(*,*) is (list-directed) formatted output.

    As to how you can solve this problem: at some point you have to decide what your unlimited polymorphic entity is. Part of the reason working with unlimited polymorphic entities is tricky is because intrinsic and derived types cannot be treated the same. As with your previous question, if you can use class(something_not_star) instead of class(*) you will find life easier.

    With things how they are, select type is probably your best hope.


    1 Defined I/O procedures may exist only for derived types.