Generics in Elixir
Elixir introduced protocols as a way to achieve polymorphism, which can be used to implement behavior similar to generics in some cases. However, Elixir doesn’t have a direct equivalent to Go’s generics. We’ll use protocols and other Elixir features to demonstrate similar concepts.
defmodule Generics do
# Elixir doesn't have a direct equivalent to Go's generics,
# but we can use protocols to achieve similar functionality.
# Here's an example of a protocol that can work with any
# enumerable type.
defprotocol Findable do
@doc "Finds the index of an element in an enumerable"
def find_index(enumerable, element)
end
# Implement the protocol for List
defimpl Findable, for: List do
def find_index(list, element) do
Enum.find_index(list, &(&1 == element))
end
end
# Implement the protocol for other enumerables
defimpl Findable, for: Enumerable do
def find_index(enumerable, element) do
enumerable
|> Enum.with_index()
|> Enum.find(fn {e, _} -> e == element end)
|> case do
{_, index} -> index
nil -> -1
end
end
end
# Define a custom linked list
defmodule LinkedList do
defstruct [:head, :tail]
def new, do: %LinkedList{}
def push(%LinkedList{head: nil, tail: nil} = list, value) do
new_node = %{value: value, next: nil}
%{list | head: new_node, tail: new_node}
end
def push(%LinkedList{tail: tail} = list, value) do
new_node = %{value: value, next: nil}
%{list | tail: %{tail | next: new_node}, tail: new_node}
end
def all_elements(%LinkedList{head: head}) do
all_elements(head, [])
end
defp all_elements(nil, acc), do: Enum.reverse(acc)
defp all_elements(node, acc), do: all_elements(node.next, [node.value | acc])
end
def main do
s = ["foo", "bar", "zoo"]
# Using our Findable protocol
IO.puts("index of zoo: #{Findable.find_index(s, "zoo")}")
# Create and use our custom LinkedList
list = LinkedList.new()
|> LinkedList.push(10)
|> LinkedList.push(13)
|> LinkedList.push(23)
IO.puts("list: #{inspect(LinkedList.all_elements(list))}")
end
end
Generics.main()
In this Elixir example:
We define a
Findable
protocol that’s similar to theSlicesIndex
function in the Go example. This protocol can be implemented for different types.We implement the
Findable
protocol forList
and otherEnumerable
types.We create a custom
LinkedList
struct to demonstrate a generic data structure. In Elixir, we don’t need to specify type parameters as it’s a dynamically typed language.The
main
function demonstrates the usage of ourFindable
protocol andLinkedList
struct.
To run this program, save it as generics.exs
and use:
$ elixir generics.exs
index of zoo: 2
list: [10, 13, 23]
Note that Elixir’s approach to polymorphism and data structures is quite different from Go’s. Elixir uses protocols and pattern matching to achieve similar results to generics in statically typed languages.