Generics in Co-array Fortran

module generics_module
  implicit none

  ! In Co-array Fortran, we don't have direct support for generics.
  ! We'll simulate some aspects using derived types and interfaces.

  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

  ! This function simulates the generic SlicesIndex function
  ! It works only for character arrays
  function slices_index(s, v) result(idx)
    character(len=*), intent(in) :: s(:)
    character(len=*), intent(in) :: v
    integer :: idx
    integer :: i

    do i = 1, size(s)
      if (s(i) == v) then
        idx = i
        return
      end if
    end do
    idx = -1
  end function slices_index

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

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

    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

  character(len=3) :: s(3) = ["foo", "bar", "zoo"]
  type(list) :: int_list
  class(*), allocatable :: elements(:)
  integer :: i

  ! Using the slices_index function
  print *, "index of zoo:", slices_index(s, "zoo")

  ! 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:"
  do i = 1, size(elements)
    select type (elem => elements(i))
    type is (integer)
      print *, elem
    end select
  end do

end program main

This Co-array Fortran code attempts to replicate the functionality of the Go generics example. However, it’s important to note that Co-array Fortran doesn’t have built-in support for generics like Go does. Instead, we’ve used derived types and class(*) to simulate some aspects of generic programming.

The slices_index function is implemented only for character arrays, as Co-array Fortran doesn’t support true generic functions. The list type is implemented using class(*) to allow it to store any type of data, which is similar to how generics work, but with some limitations.

The main program demonstrates the usage of these “generic-like” implementations. It creates a list of integers, adds elements to it, and then prints all elements.

To compile and run this program, you would typically use a Co-array Fortran compiler. The exact commands may vary depending on your specific compiler and environment.

$ <compiler> generics.f90
$ ./a.out
index of zoo: 3
list:
10
13
23

This example showcases how we can implement some generic-like behavior in Co-array Fortran, even though the language doesn’t have native support for generics. The approach used here provides some flexibility, but it’s not as type-safe or as convenient as true generics in languages like Go.