fortranpolymorphismfortran2008

Polymorphic pointer to parent class not working


Consider the following class structure, which involves three separate modules:

!----------------------- in file a.f

  module parent_body_mod
  type :: face
     class(parent_body), pointer :: bPtr
  end type
  type, abstract :: parent_body
     integer i
     type(face) :: f
  end type
  end module parent_body_mod

!------------------------ in file b.f

  module body_mod
  use parent_body_mod

  type, extends(parent_body) :: body
  end type

  interface body
     procedure :: new_body
  end interface

  contains

  function new_body() result(b) 
  type(body), target :: b
  b%i = 123
  b%f%bPtr => b
  end function
  end module body_mod

!--------------------------- in file c.f

  module body_group_mod
  use body_mod
  type :: body_group
     type(body), allocatable :: b
  end type
  interface body_group
     procedure :: new_body_group
  end interface
  contains 
  function new_body_group() result(bg)
  type(body_group) :: bg

  allocate(bg%b)
  bg%b = body()

  end function
  end module body_group_mod

!------------------- The main program

  use body_group_mod

  type(body_group) :: my_bg

  my_bg = body_group()      

  print *, my_bg%b%f%bPtr%i

  end

!--------------------------------------

The expected output is 123, whereas the actual output is something random. The code is compiled using ifort version 18.0.1. Note that the same issue doesn't happen when using "body" class itself, i.e. the following works just fine:

type(body), allocatable :: my_b

allocate(my_b)

my_b = body()

print *, my_b%f%bPtr%i ! This produces 123 as expected.

Any help is appreciated.


Solution

  • The code is non conforming.

    Pointers associated with unsaved local variables of a procedure become undefined when the execution of the procedure completes (F2008 16.5.2.5 (5)). The function result b in function new_body is considered such a local variable (F2008 1.3.154.1), hence the pointer component b%f%bPtr becomes undefined after the function call.

    Function results are a little special compare to other local unsaved variables, in that their value is available longer than the variable exists - see F2008 Note 12.41 for some discussion.

    Another way of thinking of the problems is that with the statement bg%b = body(), the body on the left hand side is a different object from the body on the right hand side. The assignment just copies the value of the right hand side object - once that assignment is complete, the right hand side object ceases to exist. Nowhere is there code to say that when the value of a body object is transferred - the pointer component needs to be updated to reference the left hand side variable being assigned to. Also note that the left hand side bg%b does not have the TARGET attribute - so there is no way that a pointer can be validly associated with it anyway.