Fortran-202X-Proposals icon indicating copy to clipboard operation
Fortran-202X-Proposals copied to clipboard

Proposal: Limited Polymorphism

Open jacobwilliams opened this issue 8 years ago • 4 comments

There are many, many applications where it is desirable to have a routine argument that accepts a limited set of variable kinds or types (say integer or real). Currently there are a couple of very unsatisfactory ways to handle this:

  • Write two different versions of the routine (one with the real argument and one with the integer argument) and overload it. Not good because the code has to be duplicated. Also, very cumbersome if the routine has multiple arguments like this (then you end up having to write multiple functions with the same code). See json-fortran for an example of this.
  • Use an unlimited polymorphic input (class(*)) argument and select type inside the routine. Also not good because the code still has to be duplicated. This is also very undesirable (especially for library routine) since it isn't possible to prevent the user from passing an invalid type to this variable. If it's supposed to be pure function, you're out of luck and you probably have to error stop the program, which should never be done in a library. This also can have the problem of deeply nested select type blocks if there are multiple arguments like this (see also Issue #7).

What we need is some kind of "limited polymorphic" variable. For example:

 pure elemental function add_two_values(a,b) result( c )
 type( real, integer ),intent(in) :: a  ! can be a real or an integer but nothing else.
 type( real, integer ), intent(in) :: b  ! can be a real or an integer but nothing else.
 real(wp) :: c
 c = a + b  ! the compiler knows how to add reals and integers
end function add_two_values

Also, we need the ability to declare other variables based on what was input. For example, there could be some sort of type_of statement like this that can be used to declare variables:

pure elemental subroutine swap(a,b)
type(real, integer),intent(inout) :: a
type( type_of(a) ),intent(inout) :: b  ! must be the same type of a or it is compile time error
type( type_of(a) ) :: tmp  ! this is a local variable of the type as a
tmp = a
a = b
b = tmp
end subroutine swap

Furthermore, we don't want to have to explicitly declare all the possible real, integer, logical, character kinds. That should be easy to do with something like this:

type( real(kind=*), integer(kind=*), logical(kind=*), character(kind=*) ), intent(in) :: a

These features would solve so many problems that we have now, and could drastically reduce the error-prone code duplication that we currently have to live with in a lot of cases.

Note: really, this should be combined with #7. It is also a possible partial solution for generic programming (#5).

jacobwilliams avatar Jul 21 '17 01:07 jacobwilliams

Imagine a single function that could swap any intrinsic variable type:

pure elemental subroutine swap_anything(a,b)
type( real(kind=*), integer(kind=*), logical(kind=*), character(kind=*,len=*) ), intent(inout) :: a
type( type_of(a) ),intent(inout) :: b  ! must be the same type of a or it is compile time error
type( type_of(a) ) :: tmp  ! this is a local variable of the type as a
tmp = a
a = b
b = tmp
end subroutine swap_anything

jacobwilliams avatar Jul 21 '17 01:07 jacobwilliams

This would go a long way towards enabling generic programming and decreasing the absurd level of verbosity of OOP Fortran.

zbeekman avatar Jul 21 '17 21:07 zbeekman

Yes, and this should be considered as a low-hanging fruit because it's syntactic sugar and would not negatively impact other features of the language.

milancurcic avatar Jul 21 '17 21:07 milancurcic

Another major use case for this is automatic differentiation. For this, it is desirable to be able to have functions that accept either real, complex, or a user-defined autodiff type. If the "function" you are differentiating involves hundreds of modules and hundreds of thousands of lines of code, it just isn't feasible to have to maintain three different versions of if or to have to put select type in every single routine.

jacobwilliams avatar Jul 23 '17 15:07 jacobwilliams