Question

Suppose I have this simple class:

   Module Foo
        ...
        character(len=3), parameter :: describe_Foo=(/'BAR', 'BED', 'BOD'/)
        ...
        type :: A
            real :: value
            integer :: descriptor
        contains
            procedure :: getter
            procedure :: setter
            ...
        end type A

   contains
        function writetype(self,...)
            ...
            write(writetype,*) self%value, describe_foo(self%descriptor)
        end function writetype
   ...
   end module Foo

How can I define its interface to "write" so that every time this type is passed to the write statement it outputs the string defined by the class method writetype.

In other words, in Python parlance, can I implement the equivalent of an __str__() method?

I've found tantalizing tidbits suggesting that this is possible, see User-defined derived-type Input/Output procedures (Fortran 2003) and User-defined derived-type Input/Output procedure interfaces (Fortran 2003). These documents give ample information to write the methods I need, but it is still unclear to me how to define an interface or procedure specification so that the behavior I want occurs.

Example application:

program test
    ...
    type(A) :: bartype, bedtype
    ...
    bartype=A(120.0,1)
    bedtype=A(102.0,2)
    write(*,*) bartype,bedtype
end program test

Desired output:

>test.exe
 120.0000 BAR
 102.0000 BED
Was it helpful?

Solution

You need to have a generic WRITE(FORMATTED) binding, bound to a specific procedure that has suitable characteristics. See section 9.6.4.8 in the F2008 standard for more information.

type :: A
  real :: value
  integer :: descriptor
contains
  procedure :: writetype
  generic :: write(formatted) => writetype
end type A
...
subroutine writetype(dtv, unit, iotype, v_list, iostat, iomsg)
  ! Argument names here from the std, but you can name them differently.
  class(A), intent(in) :: dtv         ! 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, "(F9.4,1X,A)", IOSTAT=iostat, IOMSG=iomsg)  &
      dtv%value, describe_foo(dtv%descriptor)
end subroutine writetype

It is probably also worth noting that you need a compiler that implements this!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top