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:

Approach A:

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.

+3


source to share


1 answer


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 Square

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.

+4


source







All Articles