FORTRAN: data polymorphic
I am trying to hide the difference between real and complex data types. In FORTRAN 2003 I think there may be a way to do this.
The goal is to define a polymorphic allocable array whose type can be determined at runtime. Plus there is a subroutine that takes a polymorphic array to do some algebra (the same equation works for real and complex data).
To do this, I made two attempts:
module poly implicit none private type, abstract, public :: MyType contains procedure, public :: Constructor endtype MyType type, extends(MyType), public :: MyTypeR real(8), allocatable :: AllData(:) endtype MyTypeR type, extends(MyType), public :: MyTypeI complex(8), allocatable :: AllData(:) endtype MyTypeI contains subroutine Constructor(this, Nsize) class(MyType), intent(inout) :: this integer, intent(in) :: Nsize select type(this) type is(MyTypeR) allocate(this%AllData(Nsize)) type is(MyTypeI) allocate(this%AllData(Nsize)) endselect endsubroutine endmodule poly ! Algebra subroutine module Operation contains subroutine Square(Array) class(*), intent(inout) :: Array(:) select type(Array) class is(real(8)) Array = Array**2 class is(complex(8)) Array = Array**2 endselect endsubroutine Square endmodule Operation ! Main program test use poly use Operation class(MyType), allocatable :: t1, t2 integer :: i logical :: IfComplex = .true. if(IfComplex) then allocate(MyTypeI::t1) else allocate(MyTypeR::t1) endif call t1%Constructor(4) call Square(t1%AllData) endprogram test
Approach B (unrestricted polymorphic allocable variable):
module poly implicit none private type, public :: MyType class(*), allocatable :: AllData(:) contains procedure, public :: Constructor endtype MyType contains subroutine Constructor(this, Nsize, IfComplex) class(MyType), intent(inout) :: this integer, intent(in) :: Nsize logical, intent(in) :: IfComplex if(IfComplex) then allocate(complex(8)::this%AllData(Nsize)) else allocate(real(8)::this%AllData(Nsize)) endif endsubroutine endmodule poly ! Same algebra subroutine ! Main program test use poly use Operation type(MyType) :: t1, t2 integer :: i call t1%Constructor(4, .true.) call Square(t1%AllData) endprogram test
Then I have a problem with the algebra subroutine in both approaches: in the internal assignment, the variable should not be polymorphic. Any suggestion would be appreciated.
source to share
There are several problems.
In current Fortran, you cannot extend internal types. Internal types cannot appear in the EXTENDS specifier in a derived type definition.
Therefore, in Fortran 2008, the language prohibits pretending that internal types can be an ancestor type in a construct of the selected type. This prohibition is implied in the syntax rules for an instruction of type guard (TYPE IS ... CLASS IS, etc. - the CLASS IS class of type -guard-stmt is explicitly limited to a derived type specification, which excludes the use of built-in type names), which means that the corresponding Fortran 2008 compiler should issue an error message for your syntax.
(This limitation was not published in Fortran 2003, but it was added in a later Fortran 2003 patch - your Fortran 2003 compiler vendor may not have implemented it yet.)
In Fortran 2003, internal assignment was not allowed when the variable being assigned (item to the left of equals) was polymorphic. The ability to assign a polymorphic variable was added to the language in Fortran 2008.
The solution to both of the above problems is to make statements like guard in your
TYPE IS routine , not in CLASS IS.
Apart from this immediate problem (the following is more subjective and depends on what you ultimately plan to do):
In the first example, a more typical layout would be that there are two separate non-type constructor procedures, one for MyTypeR and one for MyTypeI. The algebraic operation would then be the deferred binding of the parent of MyType, which then extends it.
MyType in the second example doesn't really play a useful role - you can also use distributed unbounded polymorphic objects.
source to share