module m
  implicit none
  
  type father 
    real, allocatable :: odd_array(:)
    type(son1), allocatable :: s1 
    type(son2), allocatable :: s2
    type(son3), allocatable :: s3 
  end type 

  type son1 
    real, allocatable :: ar1(:)
  end type 

  type son2 
    real, allocatable :: ar2(:)
  end type 

  type son3 
    real, allocatable :: ar3(:)
  end type 

  interface son1
    module procedure son1_constructor
  end interface 
  
  type(father), allocatable, protected :: test(:)
contains
  function son1_constructor(size_) 
    integer, intent(in) :: size_
    type(son1) :: son1_constructor
    
    allocate(son1_constructor%ar1(size_) )
  end function

  function son2_constructor(size_) 
    integer, intent(in) :: size_
    type(son2) :: son2_constructor
    
    allocate(son2_constructor%ar2(size_) )
  end function

  function son3_constructor(size_) 
    integer, intent(in) :: size_
    type(son3) :: son3_constructor
    
    allocate(son3_constructor%ar3(size_) )
  end function

  function father_constructor(size_1, size_2, size_3, size_odd) 
    integer, intent(in) :: size_1, size_2, size_3, size_odd
    type(father) :: father_constructor
    integer :: i
    
    allocate(father_constructor%s1)
    allocate(father_constructor%s2)
    allocate(father_constructor%s3)
!    allocate(father_constructor%odd_array(size_odd)  )   ! this array's value change randomly (memory corrupted?)
    father_constructor%odd_array = [(real(i), i = 1, size_odd)]
!    father_constructor%s1 = son1_constructor(size_1)
    father_constructor%s1 = son1(size_1)    ! accessing via interface?
    father_constructor%s2 = son2_constructor(size_2)
    father_constructor%s3 = son3_constructor(size_3)
  end function
  
  subroutine setup
    allocate(test(1000)) 
    test(1) = FATHER_CONSTRUCTOR(10,12,15,100)
    print *, test(1)%odd_array(1:10)
  end subroutine 
end module m

program p
  use m
  implicit none
  call setup
  
end program p