Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

pass unlimited polymorphic subroutine as argument and other issues

Status
Not open for further replies.

FortCpp

Technical User
Sep 25, 2014
5
US
I am programming with FORTRAN oop features. Now I have a subroutine which takes another subroutine as its argument. But I want the subroutine takes unlimited polymorphic subroutine as the argument as well as normal subroutine. For example I have:

Code:
        subroutine PassFunc(MyFunc, MyInput)
            class(*), intent(inout) :: MyInput
            interface
                subroutine MyFunc(A, B)
                    class(*), intent(in) :: A
                    class(*), intent(out) :: B
                endsubroutine MyFunc
            endinterface
            class(*), allocatable :: FuncRes
            
            select type(MyInput)
            type is(real(8))
                allocate(real(8)::FuncRes)
                select type(FuncRes)
                type is(real(8))
                    call MyFunc(MyInput, FuncRes)
                    MyInput = MyInput + FuncRes**2
                endselect
            type is(complex(8))
            endselect
        endsubroutine PassFunc

        !Input Functions
        subroutine Func1(A, B)
            class(*), intent(in) :: A
            class(*), intent(out) :: B

            select type(A)
            type is(real(8))
                select type(B)
                type is(real(8))
                    B = A + 1
                endselect
            type is(complex(8))
                select type(B)
                type is(complex(8))
                    B = A - 1
                endselect
            endselect
        endsubroutine Func1
        
        subroutine Func2(A, B)
            real(8), intent(in) :: A
            real(8), intent(out) :: B
            
            B =  A + 1
        endsubroutine Func2
Questions:

[ol 1]
[li]I am only allowed to pass an unlimited polymorphic subroutine into "PassFunc". I am not be able to pass a normal function (a function without class(*)). Is there any way to make "PassFunc" take other types of functions? (Example: Func1 works but Func2 doesn't. I got access violation with IVF, though it didn't complain when compiling. Is it possible to make it work? If it is possible, I can make use of other subroutine without modifying.)[/li]
[li]In the case, the type of "FuncRes" variable depends on "MyInput". Now the only way I know is to use a nested select type. But in fact, there is no need to do this since "FuncRes" and "MyInput will always be the same type. Is there a way to reduce the nested select type? (It would be a disaster if I have many intermediate variables.)[/li]
[/ol]

Thanks for any suggestions.
 
I tried a little bit simplified example like this:
Code:
subroutine caller_proc(some_io)
  ! polymorphic argument
  class(*) :: some_io
  ...
  call my_proc(some_io, [i]result_of_some_type[/i])
end subroutine caller_proc
...
...
! and in the main program
call caller_proc([i]integer_argument[/i])
...
call caller_proc([i]real_argument[/i])
...
call caller_proc([i]complex_argument[/i])

where
1. caller_proc has one polymorphic argument
2. my_proc is defined for several argument types using generic interface

It seems to work. I will post the code soon.
 
generic_proc.f95
Code:
[COLOR=#a020f0]module[/color] procedures
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
  [COLOR=#0000ff]! generic interface for procedures[/color]
  [COLOR=#a020f0]interface[/color] my_proc
    [COLOR=#a020f0]module[/color] [COLOR=#a020f0]procedure[/color] proc_I, proc_R, proc_C
  [COLOR=#a020f0]end interface[/color] my_proc
[COLOR=#a020f0]contains[/color]
  [COLOR=#a020f0]subroutine[/color] proc_I(a, b)
    [COLOR=#2e8b57][b]integer[/b][/color] :: a,b
    b [COLOR=#804040][b]=[/b][/color] a [COLOR=#804040][b]+[/b][/color] [COLOR=#ff00ff]1[/color]
    [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'* proc_Integer: a='[/color], a, [COLOR=#ff00ff]', b='[/color], b 
  [COLOR=#a020f0]endsubroutine[/color] proc_I

  [COLOR=#a020f0]subroutine[/color] proc_R(a, b)
[COLOR=#2e8b57][b]    real[/b][/color] :: a,b
    b [COLOR=#804040][b]=[/b][/color] a [COLOR=#804040][b]-[/b][/color] [COLOR=#ff00ff]1[/color]
    [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'* proc_Real: a='[/color], a, [COLOR=#ff00ff]', b='[/color], b 
  [COLOR=#a020f0]endsubroutine[/color] proc_R
     
  [COLOR=#a020f0]subroutine[/color] proc_C(a, b)
    [COLOR=#2e8b57][b]complex[/b][/color] :: a,b
    b[COLOR=#804040][b]=[/b][/color] [COLOR=#008080]conjg[/color](a)
    [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'* proc_Complex: a='[/color], a 
    [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'                b='[/color], b 
  [COLOR=#a020f0]endsubroutine[/color] proc_C
[COLOR=#a020f0]end module[/color] procedures

[COLOR=#a020f0]program[/color] test
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]

  [COLOR=#2e8b57][b]integer[/b][/color] :: a
[COLOR=#2e8b57][b]  real[/b][/color] :: x
  [COLOR=#2e8b57][b]complex[/b][/color] :: z

  a [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]1[/color]
  [COLOR=#008080]call[/color] caller_proc(a)
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'Result: a = '[/color], a
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color])

  x [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]5.0[/color]
  [COLOR=#008080]call[/color] caller_proc(x)
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'Result: x = '[/color], x
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color])

  z [COLOR=#804040][b]=[/b][/color] ([COLOR=#ff00ff]1[/color], [COLOR=#ff00ff]1[/color])
  [COLOR=#008080]call[/color] caller_proc(z)
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'Result: z = '[/color], z
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color])  
[COLOR=#a020f0]contains[/color]
  [COLOR=#a020f0]subroutine[/color] caller_proc(some_io)
    [COLOR=#a020f0]use[/color] procedures
    [COLOR=#0000ff]! polymorphic argument[/color]
    [COLOR=#2e8b57][b]class[/b][/color]([COLOR=#804040][b]*[/b][/color]) :: some_io
    [COLOR=#0000ff]! possible data type results[/color]
    [COLOR=#2e8b57][b]integer[/b][/color] :: res_I
[COLOR=#2e8b57][b]    real[/b][/color] :: res_R
    [COLOR=#2e8b57][b]complex[/b][/color] res_C

    [COLOR=#804040][b]select type[/b][/color](some_io)
      [COLOR=#804040][b]type is[/b][/color] ([COLOR=#2e8b57][b]integer[/b][/color])
        [COLOR=#008080]call[/color] my_proc(some_io, res_I)
        some_io [COLOR=#804040][b]=[/b][/color]  some_io [COLOR=#804040][b]+[/b][/color] res_I [COLOR=#804040][b]*[/b][/color] [COLOR=#ff00ff]2[/color]
        [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'some_io = '[/color], some_io
      [COLOR=#804040][b]type is[/b][/color] (real)
        [COLOR=#008080]call[/color] my_proc(some_io, res_R)
        some_io [COLOR=#804040][b]=[/b][/color]  some_io [COLOR=#804040][b]+[/b][/color] res_R [COLOR=#804040][b]*[/b][/color] [COLOR=#ff00ff]2[/color]
        [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'some_io = '[/color], some_io
      [COLOR=#804040][b]type is[/b][/color] ([COLOR=#2e8b57][b]complex[/b][/color])
        [COLOR=#008080]call[/color] my_proc(some_io, res_C)
        some_io [COLOR=#804040][b]=[/b][/color]  some_io [COLOR=#804040][b]+[/b][/color] res_C [COLOR=#804040][b]*[/b][/color] [COLOR=#ff00ff]2[/color]
        [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'some_io = '[/color], some_io
    [COLOR=#804040][b]end select[/b][/color]
  [COLOR=#a020f0]end subroutine[/color] caller_proc    
[COLOR=#a020f0]end program[/color] test

Output:
Code:
$ gfortran generic_proc.f95 -o generic_proc

MIKL1071@MIKL1071 ~/fortran
$ generic_proc
 * proc_Integer: a=           1 , b=           2
 some_io =            5
 Result: a =            5

 * proc_Real: a=   5.00000000     , b=   4.00000000
 some_io =    13.0000000
 Result: x =    13.0000000

 * proc_Complex: a= (  1.00000000    ,  1.00000000    )
                 b= (  1.00000000    , -1.00000000    )
 some_io =  (  3.00000000    , -1.00000000    )
 Result: z =  (  3.00000000    , -1.00000000    )
 
Thanks for your time and response mikrom. But I think there is some misunderstand here. In your example code, you shown that "a subroutine can take unlimited polymorphic types as imput parameters". My question is "Is it possible to make subroutine take unlimited polymorphic subroutines as well as normal subroutines as input parameters".
For example:

you can have

Code:
subroutine poly(A)
class(*), intent(inout) :: A
I understand this is possible in FORTRAN. You also mentioned that one can use an interface for putting different subroutines together for processing the parameter. In fact, you can use the 3 proc subroutines without the interface as well.

But my question is: If you have

Code:
subroutine poly(another_subroutine, A)
class(*), intent(inout) :: A 
interface
subroutine another_subroutine(AA)
class(*), intent(inout) ::AA
endsubroutine
endinterface

(please note here: the interface is used to define how the passing-in subroutine should be. Not a generic thing) This subroutine can take other subroutines (which fit the interface) as input. But it doesn't take a normal subroutine (a subroutine without unlimited polymorphic parameters) as input. I am wondering if there is a work around to it. If you have any suggestions, please let me know. Thanks again.
 
Hi FortCpp,
I only tried to get around it without passing subroutine as an argument of other subroutine, because IMO for this purpose generic interface could be used.

This subroutine can take other subroutines (which fit the interface) as input. But it doesn't take a normal subroutine (a subroutine without unlimited polymorphic parameters) as input.
Yes it doesn't take subroutine with normal argument, because in the procedure interface you have declared, that it should only accept subroutine with polymorphic type.
 
mikrom,

Yes, I agree. But it doesn't compile if I make interface generic. For example
Code:
subroutine poly(another_subroutine, A)
class(*), intent(inout) :: A 
interface another_subroutine
subroutine another_subroutine(AA)
class(*), intent(inout) ::AA
endsubroutine
subroutine another_subroutine(AA)
real(8), intent(inout) ::AA
endsubroutine
endinterface another_subroutine
Is there a way to rewrite it somehow?
 
Sorry, I made some grammar mistakes in the code, I have no idea how to edit the reply.
 
Hi FortCpp,
I tried to declare the procedure name argument without interface using the key word external.
It seems to work. Now the caller procedure calls normal procedures (integer, real, complex) and the polymorphic procedure too. However, the polymotphic procedure only prints something, because I don't know how to do some computation inside of it. Everytime when I try it I get an error: Program received signal SIGSEGV: Segmentation fault - invalid memory reference.

Here is the code:
Code:
[COLOR=#a020f0]program[/color] test
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]

  [COLOR=#2e8b57][b]integer[/b][/color] :: a
[COLOR=#2e8b57][b]  real[/b][/color] :: x
  [COLOR=#2e8b57][b]complex[/b][/color] :: z

  a [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]1[/color]
  [COLOR=#008080]call[/color] caller_proc(proc_I, a)
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'Result: a = '[/color], a
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color])

  x [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]5.0[/color]
  [COLOR=#008080]call[/color] caller_proc(proc_R, x)
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'Result: x = '[/color], x
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color])

  z [COLOR=#804040][b]=[/b][/color] ([COLOR=#ff00ff]1[/color], [COLOR=#ff00ff]1[/color])
  [COLOR=#008080]call[/color] caller_proc(proc_C, z)
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'Result: z = '[/color], z
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color])

  x [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]2.0[/color]
  [COLOR=#008080]call[/color] caller_proc(proc_P, x)
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'Result: x = '[/color], x
  [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color])
[COLOR=#a020f0]contains[/color]

  [COLOR=#a020f0]subroutine[/color] caller_proc(my_proc, some_io)
    [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
    [COLOR=#0000ff]! my_proc is external subroutine[/color]
    [COLOR=#2e8b57][b]external[/b][/color] my_proc
    [COLOR=#0000ff]! polymorphic argument[/color]
    [COLOR=#2e8b57][b]class[/b][/color]([COLOR=#804040][b]*[/b][/color]) :: some_io
    [COLOR=#0000ff]! possible data type results[/color]
    [COLOR=#2e8b57][b]integer[/b][/color] :: res_I
[COLOR=#2e8b57][b]    real[/b][/color] :: res_R
    [COLOR=#2e8b57][b]complex[/b][/color] :: res_C
    [COLOR=#2e8b57][b]class[/b][/color]([COLOR=#804040][b]*[/b][/color]), [COLOR=#2e8b57][b]allocatable[/b][/color] :: res_P

    [COLOR=#804040][b]select type[/b][/color](some_io)
      [COLOR=#804040][b]type is[/b][/color] ([COLOR=#2e8b57][b]integer[/b][/color])
        [COLOR=#008080]call[/color] my_proc(some_io, res_I)
        some_io [COLOR=#804040][b]=[/b][/color]  some_io [COLOR=#804040][b]+[/b][/color] res_I [COLOR=#804040][b]*[/b][/color] [COLOR=#ff00ff]2[/color]
        [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'some_io = '[/color], some_io
      [COLOR=#804040][b]type is[/b][/color] (real)
        [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'*Type is real '[/color]
        [COLOR=#008080]call[/color] my_proc(some_io, res_R)
        some_io [COLOR=#804040][b]=[/b][/color]  some_io [COLOR=#804040][b]+[/b][/color] res_R [COLOR=#804040][b]*[/b][/color] [COLOR=#ff00ff]2[/color]
        [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'some_io = '[/color], some_io
      [COLOR=#804040][b]type is[/b][/color] ([COLOR=#2e8b57][b]complex[/b][/color])
        [COLOR=#008080]call[/color] my_proc(some_io, res_C)
        some_io [COLOR=#804040][b]=[/b][/color]  some_io [COLOR=#804040][b]+[/b][/color] res_C [COLOR=#804040][b]*[/b][/color] [COLOR=#ff00ff]2[/color]
        [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'some_io = '[/color], some_io
    [COLOR=#804040][b]end select[/b][/color]
  [COLOR=#a020f0]end subroutine[/color] caller_proc

  [COLOR=#a020f0]subroutine[/color] proc_I(a, b)
    [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
    [COLOR=#2e8b57][b]integer[/b][/color] :: a,b
    b [COLOR=#804040][b]=[/b][/color] a [COLOR=#804040][b]+[/b][/color] [COLOR=#ff00ff]1[/color]
    [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'* proc_Integer: a='[/color], a, [COLOR=#ff00ff]', b='[/color], b 
  [COLOR=#a020f0]endsubroutine[/color] proc_I

  [COLOR=#a020f0]subroutine[/color] proc_R(a, b)
    [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
[COLOR=#2e8b57][b]    real[/b][/color] :: a,b
    b [COLOR=#804040][b]=[/b][/color] a [COLOR=#804040][b]-[/b][/color] [COLOR=#ff00ff]1[/color]
    [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'* proc_Real: a='[/color], a, [COLOR=#ff00ff]', b='[/color], b 
  [COLOR=#a020f0]endsubroutine[/color] proc_R
     
  [COLOR=#a020f0]subroutine[/color] proc_C(a, b)
    [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
    [COLOR=#2e8b57][b]complex[/b][/color] :: a,b
    b[COLOR=#804040][b]=[/b][/color] [COLOR=#008080]conjg[/color](a)
    [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'* proc_Complex: a='[/color], a 
    [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'                b='[/color], b 
  [COLOR=#a020f0]endsubroutine[/color] proc_C

  [COLOR=#a020f0]subroutine[/color] proc_P(a, b)
    [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
    [COLOR=#2e8b57][b]class[/b][/color]([COLOR=#804040][b]*[/b][/color]) :: a, b
    [COLOR=#804040][b]write[/b][/color]([COLOR=#804040][b]*[/b][/color],[COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'** Hello from Polymorphic procedure !'[/color]
  [COLOR=#a020f0]endsubroutine[/color] proc_P
[COLOR=#a020f0]end program[/color] test

and here is the output:
Code:
$ gfortran subroutine_arg.f95 -o subroutine_arg

$ subroutine_arg
 * proc_Integer: a=           1 , b=           2
 some_io =            5
 Result: a =            5

 *Type is real
 * proc_Real: a=   5.00000000     , b=   4.00000000
 some_io =    13.0000000
 Result: x =    13.0000000

 * proc_Complex: a= (  1.00000000    ,  1.00000000    )
                 b= (  1.00000000    , -1.00000000    )
 some_io =  (  3.00000000    , -1.00000000    )
 Result: z =  (  3.00000000    , -1.00000000    )

 *Type is real
 ** Hello from Polymorphic procedure !
 some_io =    2.00000000
 Result: x =    2.00000000
 
mikrom,

Thanks for the response. To me, "external" contains no information of the subroutine. My understanding is: "external" can be anything and the language leave this room for the linker. I don't know for sure why there is a seg fault. But I'd expect this is due to the FORTRAN standard doesn't define such kind of thing. So I'd say one cannot use unlimited poly and normal subroutines at the same time but "external" is a option (but the result could be wrong).

I appreciate your code and time.
 
Hi FortCpp,

I tried eveything above with gfortran compiler, but maybe the behavior with polymorphic subroutines is better implemented in other compiler.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top