is there a cleaner way to express the derived type other than select type clause?

Viewed 102

in the code below, I am using derived type functions to be able to have a common api for generating new derived types from current objects. I realize that the compiler can't get type information from allocate statements as the object could also be deallocated and reallocated as something else, but I am curious if there is a cleaner way to work with the allocated object as the proper derived type other than a select type statement. Something about it just feels funny since within the function I absolutely know what its type is even if the compiler doesn't

module poly

  implicit none

  type, abstract :: parent
   contains
     procedure(i_new_child), deferred, pass(this) :: new_child
  end type parent

  interface
     function i_new_child(this) result(child)
       import
       class(parent), intent(in) :: this
       class(parent), allocatable :: child
     end function i_new_child
  end interface

  type, extends(parent) :: child1
     integer :: a
   contains
     procedure, pass(this) :: new_child => new_child1
  end type child1

contains

  function new_child1(this) result(child)
    class(child1), intent(in) :: this
    class(parent), allocatable :: child
    allocate(child1 :: child)
    ! child%a = 1  ! 'a' at (1) is not a member of the 'parent' structure
    select type (child)
       class is (child1)
          child%a = 1
    end select
  end function new_child1

end module poly
1 Answers

In cases where "complicated" construction is required, allocate a variable of the concrete type and then MOVE_ALLOC that variable across to the result.

function new_child1(this) result(child)
  class(child1), intent(in) :: this
  class(parent), allocatable :: child
  type(child1), allocatable :: tmp
  
  allocate(tmp)
  tmp%a = 1
  ! Real world complex construction goes here.
  ! Once construction of tmp is complete:
  call move_alloc(tmp, child)
end function new_child1

For trivial/simple construction, use the structure constructor in combination with automatic allocation on assignment to a polymorphic variable.

function new_child1(this) result(child)
  class(child1), intent(in) :: this
  class(parent), allocatable :: child
  
  child = child1(a=1)
end function new_child1
Related