Function overloading in Fortran 2008

1.3k views Asked by At

I'm beginning with Fortran 2008 and I'm struggling with OOP greatly. It seems, that there are very few materials, which explain a very basic OOP concepts in 2008 language standard.

I've found information about inheritance, but I was unable to find any info about polymorphism.

So if I wanted to overload a function in C++, I can do it like this (example from Wikipedia):

// volume of a cube
int volume(const int s)
{
    return s*s*s;
}

// volume of a cylinder
double volume(const double r, const int h)
{
    return 3.1415926*r*r*static_cast<double>(h);
}

// volume of a cuboid
long volume(const long l, const int b, const int h)
{
    return l*b*h;
}

But, how am I supposed to do the same thing in Fortran 2008?

2

There are 2 answers

2
francescalus On BEST ANSWER

The idea of overloading as given in the C++ examples has an implementation in Fortran, dating back to the generics of Fortran 90.

Given a set of specific procedures a generic identifier may be used to identify this set. In this answer I'll give a very high-level introduction to this concept. There are a lot of subtleties which may require further reading/questions to address.

Unlike the C++ example, our Fortran specific procedures need to be named separately. Let's have the two functions (third can be added mutatis mutandis)

integer function volume_cube(s)
  integer, intent(in) :: s
  ...
end function volume_cube

double precision function volume_cylinder(r, h)
  double precision, intent(in) :: r
  integer, intent(in) :: h
  ...
end function volume_cylinder

We can then add a generic interface for something called volume:

interface volume
  procedure volume_cube, volume_cylinder
end interface

We can then reference the generic volume and the compiler will determine which specific function to use.

There is much more to learn about generics, including what else they offer beyond this simple overloading. One should also understand how specific procedures are resolved (simple in this case, not so in others) and the restrictions on which specific procedures may be lumped together. As you use generics problematic cases are likely to have particular questions. I answer here only as I couldn't see an introductory question and I don't attempt to address the many varied difficulties or values.


Complete example

module mod

  private

  interface volume
     module procedure volume_cube, volume_cylinder
  end interface volume
  public volume

contains
  integer function volume_cube(s)
    integer, intent(in) :: s
    volume_cube = s**3
  end function volume_cube

  double precision function volume_cylinder(r, h)
    double precision, intent(in) :: r
    integer, intent(in) :: h
    volume_cylinder = 3.1415926d0*r**2*h
  end function volume_cylinder

end module mod

  use mod

  print*, volume(2), volume(2d0,4)
end
0
Holmz On

expanding Fancescalus example:

module Pablo_Dali
private

interface volume_Cube
  module procedure volume_cube_Int, volume_cube_Float, Colume_cube_Double
!add in 8, 16, and 64 bit ints... and complex??
end interface volume
public volume_Cube

contains
  integer function volume_cube_Int(s)
    integer, intent(in) :: s
    volume_cube_Int = s**3
  end function volume_cube_int

  float function volume_cube_Float(s)
    float, intent(in) :: s
    volume_cube_float = s**3
  end function volume_cube_Float

  integer function volume_cube_Double(s)
    DOUBLE, intent(in) :: s
    volume_cube_Double = s**3
  end function volume_cube_Double
end module Pablo_Dali

then the code:

PROGRAM Cube_Volume
USE Pablo_Dali
IMPLICIT NONE

INTEGER :: I_Side, I_Volume
FLOAT   :: F_Side, F_Volume
DOUBLE  :: D_Side, D_Volume

I_Side = 1
F_Side = 1.0E0
D_Side = 1.0D0

WRITE(*,*)'[INT]    ',I_Side,' cubed=', volume_cube(I_Side)
WRITE(*,*)'[FLOAT]  ',F_Side,' cubed=', volume_cube(F_Side)
WRITE(*,*)'[DOUBLE] ',D_Side,' cubed=', volume_cube(D_Side)

END PROGRAM Cube_Volume