Generics in Fortran

module generics_module
  implicit none

  ! As an example of a generic type, we'll create a singly-linked list
  ! with values of any type using Fortran's unlimited polymorphic feature.
  type :: list_node
    class(*), allocatable :: value
    type(list_node), pointer :: next => null()
  end type list_node

  type :: list
    type(list_node), pointer :: head => null()
    type(list_node), pointer :: tail => null()
  contains
    procedure :: push
    procedure :: all_elements
  end type list

contains

  ! As Fortran doesn't have a direct equivalent to Go's SlicesIndex function,
  ! we'll implement a similar function for integer arrays
  function slices_index(arr, val) result(index)
    integer, intent(in) :: arr(:)
    integer, intent(in) :: val
    integer :: index
    integer :: i

    do i = 1, size(arr)
      if (arr(i) == val) then
        index = i
        return
      end if
    end do
    index = -1
  end function slices_index

  ! Push method for the list type
  subroutine push(this, value)
    class(list), intent(inout) :: this
    class(*), intent(in) :: value
    type(list_node), pointer :: new_node

    allocate(new_node)
    allocate(new_node%value, source=value)

    if (.not. associated(this%tail)) then
      this%head => new_node
      this%tail => new_node
    else
      this%tail%next => new_node
      this%tail => new_node
    end if
  end subroutine push

  ! All_elements method for the list type
  function all_elements(this) result(elems)
    class(list), intent(in) :: this
    class(*), allocatable :: elems(:)
    type(list_node), pointer :: current
    integer :: count, i

    count = 0
    current => this%head
    do while (associated(current))
      count = count + 1
      current => current%next
    end do

    allocate(elems(count))

    current => this%head
    do i = 1, count
      elems(i) = current%value
      current => current%next
    end do
  end function all_elements

end module generics_module

program main
  use generics_module
  implicit none

  integer :: arr(3) = [10, 20, 30]
  type(list) :: int_list
  class(*), allocatable :: elements(:)
  integer :: i

  ! Using the slices_index function
  print *, "Index of 20:", slices_index(arr, 20)

  ! Using the list type
  call int_list%push(10)
  call int_list%push(13)
  call int_list%push(23)

  elements = int_list%all_elements()

  print *, "List elements:"
  do i = 1, size(elements)
    select type (elem => elements(i))
      type is (integer)
        print *, elem
    end select
  end do

end program main

This Fortran code demonstrates concepts similar to those in the Go generics example:

  1. We’ve created a module generics_module to encapsulate our generic types and functions.

  2. Instead of Go’s generics, we’ve used Fortran’s unlimited polymorphic feature (class(*)) to create a list that can hold any type of data.

  3. The slices_index function is implemented for integer arrays, as Fortran doesn’t have a direct equivalent to Go’s generic SlicesIndex function.

  4. We’ve created a list type with push and all_elements methods, similar to the Go example.

  5. In the main program, we demonstrate the use of slices_index and the list type.

To compile and run this Fortran program:

$ gfortran -o generics generics.f90
$ ./generics

Note that Fortran’s approach to generic programming is different from Go’s. Fortran uses features like unlimited polymorphic types and type-bound procedures to achieve similar functionality. The exact output may vary depending on the Fortran compiler and version used.