Skip to content

Finalization order for complex objects: official interpretation needed? #146

Open
@nncarlson

Description

@nncarlson

@certik asked that I share this here.

I've encountered an issue with finalization that is illustrated by the example that follows. There is a parent type and child type that extends the parent, each with a final subroutine. The child type has two derived type components, one allocatable, the other not. The component types also have final subroutines. The point of the example is to reveal the order in which the final subroutines are called.

Two compilers produce the results I expected, namely the string "CABP" for Child, component A, component B, and Parent. "CBAP" would have been equally acceptable. A third compiler produces the string "CBPA". The preliminary response from the vendor of the latter compiler is that the standard is ambiguous with conflicting requirements and that choice of behavior is arguably valid. They did go into some explanation, but I haven't yet understood their argument. I'll be following up with them, and as I understand more I'll comment here with it. Section 7.5.6.2 (2018) seems pretty clear to me (arguing for "CABP") but there may well be other parts of the standard that are inconsistent with it -- I have a lot of respect for this vendor. If an official interpretation and standard clarification is required I would strongly urge for "CABP".

[Edit] The core question here is why does the third compiler vendor believe the allocatable component A have to be finalized last after the parent, whereas the non-allocatable component B should be finalized before the parent.

Here is the example

module child_type

  implicit none
  private

  type :: objectA
  contains
    final :: finalize_objectA
  end type

  type :: objectB
  contains
    final :: finalize_objectB
  end type

  type :: parent
  contains
    final :: finalize_parent
  end type

  type, extends(parent), public :: child
    type(objectA), allocatable :: A
    type(objectB) :: B
  contains
    procedure :: init
    final :: finalize_child
  end type

contains

  subroutine finalize_objectA(this)
    type(objectA), intent(inout) :: this
    write(*,'("A")',advance='no')
  end subroutine

  subroutine finalize_objectB(this)
    type(objectB), intent(inout) :: this
    write(*,'("B")',advance='no')
  end subroutine

  subroutine finalize_parent(this)
    type(parent), intent(inout) :: this
    write(*,'("P")',advance='no')
  end subroutine

  subroutine finalize_child(this)
    type(child), intent(inout) :: this
    write(*,'("C")',advance='no')
  end subroutine

  subroutine init(this)
    class(child), intent(inout) :: this
    allocate(this%A)
  end subroutine

end module

program main
  use child_type
  call run
contains
  subroutine run
    type(child) :: c
    call c%init
  end subroutine
end program

Metadata

Metadata

Assignees

No one assigned

    Labels

    Clause 7Standard Clause 7: Types

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions