Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Limited Polymorphism #10

Open
jacobwilliams opened this issue Jul 21, 2017 · 4 comments
Open

Proposal: Limited Polymorphism #10

jacobwilliams opened this issue Jul 21, 2017 · 4 comments

Comments

@jacobwilliams
Copy link
Member

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 Proposal: More flexible SELECT TYPE #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
Copy link
Member Author

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

@zbeekman
Copy link
Member

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

@milancurcic
Copy link

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.

@jacobwilliams
Copy link
Member Author

jacobwilliams commented Jul 23, 2017

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants