admin管理员组

文章数量:1124390

In OOP Fortran, we are using derived types to exchange data with external files via a namelist. I dislike that when you write a namelist to a file, the full inheritance tree is included in the variable name.

Consider this MWE:

program main

  type                     :: parenttype
    integer                :: parentvar
  end type

  type,extends(parenttype) :: childtype
    integer                :: childvar
  end type

  type(childtype) :: ioobj

  namelist /ionml/ ioobj

  ! Using "shallow" paths to member variables in the code.
  ioobj%parentvar = -1
  ioobj%childvar  = -2

  ! Read "shallow" nml file (depth 2 for variables from all inheritance levels)
  open(unit=1, file="in.nml", status="OLD")
  read(unit=1, nml=ionml)
  close(unit=1)

  ioobj%parentvar = ioobj%parentvar + 1
  ioobj%childvar  = ioobj%childvar  + 1

  ! Write "deep" nml file (name includes parents, depth will depend on inheritance level)
  open(unit=2, file="out.nml", status="NEW")
  write(unit=2, nml=ionml)
  close(unit=2)

  ! Read "deep" nml file (works just as with the "shallow" file)
  open(unit=3, file="out.nml", status="OLD")
  read(unit=3, nml=ionml)
  close(unit=3)

  print*, "parent var:", ioobj%parentvar, " child var:", ioobj%childvar
end program

Now take the following namelist file in.nml. Let's call its format “shallow”, since the variables inside ioobj are all addressed without extra steps:

&ionml
ioobj%parentvar = 9
ioobj%childvar = 13
/

The program reads this file, and writes an out.nml whose entries have a “deep” format:

&IONML
 IOOBJ%PARENTTYPE%PARENTVAR=10         ,
 IOOBJ%CHILDVAR=14         ,
 /

(This is the output from gfortran 11.4.0; the result from ifort 2021.7.0 is the same up to whitespace.)

From the Fortran side of things, both namelist files are behaving equivalently (the namelist parser accepts both the “shallow” format ionml%parentvar and the “deep” format ionml%parenttype%parentvar), so far so good. I still would like to have control over this (i. e. decide against the “deep” variant, and in favor of the “shallow” variant), for various reasons:

  • Inclusion of the inheritance hierarchy is redundant, since the origin of a member variable is known anyway.
  • It is a cluttered interface. End users are distracted with information that they do not need to know. In post-processing, this encourages anti-patterns of including boilerplate and/or ugly workarounds (I've seen all of this).
  • Increased size of input files, information dilution.
  • Risk for breaking compatibility when internally refactoring the hierarchy (parsing will fail, even if great care has been taken to keep the “shallow” API intact)
  • External tools (e. g. post-processing via f90nml) don't know that the two formats are equivalent. Additional overhead is necessary to use the input and output files interchangeably.
  • It just feels wrong to address member variable with a different depth in the code vs. the namelist files. (Violation of the principle of least astonishment.) Fair enough, I could also use the “deep” variant ioobj%parenttype%parentvar directly in the Fortran code, but this not just doesn't solve the incoherence between the two formats, but IMHO also defeats the purpose of object orientation (separation of interface and implementation).

Can I modify the write process for namelists, so that it produces the “shallow” format rather than the “deep” format?

I have not found any hint of doing so in the ifort documentation and the Oracle language reference. I would consider monkey-patching (sed -i 's/%[^ =]*%/%/') only as the very desperate last resort.

本文标签: fortranShallow vs deep namelist writeStack Overflow