Polymorphism in fortran

1.3k views Asked by At

I have a code similar to:

Module C_sys

  use class_A

   implicit none

    Private

    Type, public :: C_sys_type

  private

   logical   :: Ao_set = .false. 

   type(A) :: Ao

 Contains

 Private

    Procedure, public :: get_Ao
    Procedure, public :: set_Ao

 End Type C_sys_type

  interface C_sys_type

   Procedure C_sys_type_constructor

  end interface C_sys_type

 Contains

type(C_sys_type) elemental function C_sys_type_constructor(Ao) result(C_sys)

   type(A), intent(in), optional :: Ao

    C_sys % Ao = Ao
   C_sys % Ao_set = .true.

end function C_sys_type_constructor

type(A) elemental function get_Ao 
  class(C_sys_type), intent(in) :: this

   get_Ao = this % Ao
 end function get_Ao

 subroutine set_Ao(this, Ao)

 class(C_sys_type), intent(inout) :: this
 type(Ao), intent(in)             :: Ao

   this % Ao     = Ao  
   this % Ao_set = .true.

end subroutine set_Ao

End Module C_sys

I am not sure where in the subroutine set_Ao , type(Ao), intent(in) :: Ao should be left like this or instead to have class(Ao), intent(in) :: Ao. I know that class(Ao) is making the variable polymorphic and accessing the data type of A. But I don't know when it has to be used one or the other.

Thanks.

1

There are 1 answers

0
aphirst On BEST ANSWER

If you want to be able to bind a function/subroutine to a derived type (and for that routine to be able to access/modify the members of an instance of that type, which is the usual use-case; referred to as "PASSing" a variable), you need to meet the following conditions:

  • The TYPE definition must contain an appropriate PROCEDURE line (either with PASS explicitly stated, or there by-default whenever NOPASS is not specified).
  • The function/subroutine have at least one dummy argument of the TYPE in question, which must be declared in the argument list with CLASS (subject to all the restrictions that entails).
    • The reason it needs CLASS for this is that some other TYPE might "extend" your TYPE, which would mean it inherits its members - this can only work if the member routines are data-polymorphic.

I've attempted to modify your provided code sample into something representative of what I think you actually meant, but which actually compiles, to hopefully demonstrate correct usage.

module c_sys
  implicit none

  private

  type, public :: a
    integer :: i
  end type

  type, public :: c_sys_type
    private
    logical :: ao_set = .false.
    type(a) :: ao
  contains
    private
    procedure, public :: get_ao
    procedure, public :: set_ao
  end type c_sys_type

  interface c_sys_type
    procedure c_sys_type_constructor
  end interface c_sys_type

contains

  type(c_sys_type) elemental function c_sys_type_constructor(ao) result(c_sys)
    type(a), intent(in), optional :: ao

    c_sys % ao = ao
    c_sys % ao_set = .true.
  end function c_sys_type_constructor

  type(a) elemental function get_ao(this)
    class(c_sys_type), intent(in) :: this

    get_ao = this % ao
  end function get_ao

  subroutine set_ao(this, ao)
    class(c_sys_type), intent(inout) :: this
    type(a),           intent(in)    :: ao

    this % ao     = ao
    this % ao_set = .true.
  end subroutine set_ao

end module c_sys
  • I assume your TYPE A and TYPE AO were defined in the CLASS_A module you haven't provided. I've declared a dummy type in my version.

Things can get more complex if you want to make use of NOPASS etc., but for "normal" usage I hope this answers your question.