fortranpolymorphismoverloadingfortran2008

Function overloading in Fortran 2008


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?


Solution

  • 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