Interfaces in Fortran

In Fortran, we can define abstract interfaces that are similar to Go’s interfaces. However, Fortran uses abstract types and type-bound procedures to achieve similar functionality. Let’s see how we can implement the geometry example in Fortran.

module geometry_module
    implicit none
    
    ! Define an abstract type for geometric shapes
    type, abstract :: geometry
    contains
        procedure(area_interface), deferred :: area
        procedure(perim_interface), deferred :: perim
    end type geometry

    ! Define the interfaces for area and perimeter
    abstract interface
        function area_interface(this) result(res)
            import geometry
            class(geometry), intent(in) :: this
            real :: res
        end function area_interface

        function perim_interface(this) result(res)
            import geometry
            class(geometry), intent(in) :: this
            real :: res
        end function perim_interface
    end interface

    ! Define rect type
    type, extends(geometry) :: rect
        real :: width, height
    contains
        procedure :: area => rect_area
        procedure :: perim => rect_perim
    end type rect

    ! Define circle type
    type, extends(geometry) :: circle
        real :: radius
    contains
        procedure :: area => circle_area
        procedure :: perim => circle_perim
    end type circle

contains
    ! Implement area and perimeter for rect
    function rect_area(this) result(res)
        class(rect), intent(in) :: this
        real :: res
        res = this%width * this%height
    end function rect_area

    function rect_perim(this) result(res)
        class(rect), intent(in) :: this
        real :: res
        res = 2 * (this%width + this%height)
    end function rect_perim

    ! Implement area and perimeter for circle
    function circle_area(this) result(res)
        class(circle), intent(in) :: this
        real :: res
        real, parameter :: pi = 3.14159265359
        res = pi * this%radius**2
    end function circle_area

    function circle_perim(this) result(res)
        class(circle), intent(in) :: this
        real :: res
        real, parameter :: pi = 3.14159265359
        res = 2 * pi * this%radius
    end function circle_perim

    ! Generic measure subroutine
    subroutine measure(g)
        class(geometry), intent(in) :: g
        print *, "Area:", g%area()
        print *, "Perimeter:", g%perim()
    end subroutine measure
end module geometry_module

program main
    use geometry_module
    implicit none

    type(rect) :: r
    type(circle) :: c

    r = rect(width=3.0, height=4.0)
    c = circle(radius=5.0)

    print *, "Rectangle:"
    call measure(r)

    print *, "Circle:"
    call measure(c)
end program main

In this Fortran implementation:

  1. We define an abstract type geometry with deferred procedures area and perim.

  2. We create concrete types rect and circle that extend the geometry type and implement the required procedures.

  3. The measure subroutine takes a geometry class argument, allowing it to work with any type that extends geometry.

  4. In the main program, we create instances of rect and circle and pass them to the measure subroutine.

To compile and run this Fortran program:

$ gfortran -o geometry geometry.f90
$ ./geometry

This will output the area and perimeter of the rectangle and circle.

While Fortran doesn’t have interfaces in the same way as Go, abstract types and type-bound procedures provide similar functionality, allowing for polymorphic behavior and code reuse.