Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

interfaced type-bound procedures in Fortran

I am trying to define an interfaced procedure as a type-bound procedure in a Fortran type definition, but it seems it doesn't work as one would expect. Consider the following module:

module example_module
implicit none
private

interface add_them
  module procedure add_them_integer,add_them_real
end interface add_them

type, public :: foo
  integer, private :: a=1,b=2
  real, private :: c=4.,d=5.
contains
  procedure, public :: add => add_them
end type foo

contains
subroutine add_them_integer(self,x)
class(foo), intent(in) :: self
integer, intent(in) :: x
print *,self%a+self%b+x
end subroutine add_them_integer

subroutine add_them_real(self,x)
class(foo), intent(in) :: self
real, intent(in) :: x
print *,self%c+self%d+x
end subroutine add_them_real
end module example_module

and the corresponding program that uses the module:

program example
use example_module
implicit none
type(foo) :: foofoo
call foofoo%add(1)
call foofoo%add(2.)
end program example

I would expect this to compile and results should be 4 and 11. However, gfortran reports the following error:

procedure, public :: add => add_them
         1
Error: 'add_them' must be a module procedure or an external procedure with an explicit interface at (1)

A workaround is to use generic type-bound procedure instead of an interfaced one, so that the module is as follows:

module example_module
implicit none
private

type, public :: foo
  integer, private :: a=1,b=2
  real, private :: c=4.,d=5.
contains
  generic, public :: add => add_them_integer,add_them_real
  procedure, private :: add_them_integer,add_them_real
end type foo

contains
subroutine add_them_integer(self,x)
class(foo), intent(in) :: self
integer, intent(in) :: x
print *,self%a+self%b+x
end subroutine add_them_integer

subroutine add_them_real(self,x)
class(foo), intent(in) :: self
real, intent(in) :: x
print *,self%c+self%d+x
end subroutine add_them_real
end module example_module

This works as expected. However, I cannot use a generic procedure. The above is just a simplified example to demonstrate the problem, but in my actual code 'add_them' cannot be a generic procedure because 'foo' is actually a derived-type and 'add_them' overrides a procedure defined in the parent type; gfortran (at least) does not allow generic procedures overriding base procedures. To bypass this restriction, I thought I should use an interface instead, but as you can see in the above example, although 'add_them' is defined correctly, compiler complains that "'add_them' must be a module procedure or an external procedure with an explicit interface".

Any help would be appreciated; thanks in advance.

like image 998
Pap Avatar asked Dec 07 '13 01:12

Pap


1 Answers

The gfortran error for your first section of code is correct. The way to do generic bindings is as per your "works as expected" section of code.

If a parent type has a specific binding with a certain name, then you cannot reuse that name in extensions, other than to override the specific binding.

If you want add (note the name add_them doesn't appear in your second case) to be a generic binding in extensions, then make it a generic binding in the parent.

like image 121
IanH Avatar answered Sep 23 '22 09:09

IanH