Generics in Erlang

In Erlang, there isn’t a direct equivalent to Go’s generics. However, we can demonstrate similar concepts using Erlang’s pattern matching and dynamic typing. Let’s explore how we can implement similar functionality.

-module(generics).
-export([main/0]).

% SlicesIndex function equivalent
slices_index(List, Value) ->
    slices_index(List, Value, 0).

slices_index([], _, _) ->
    -1;
slices_index([H|T], Value, Index) ->
    case H =:= Value of
        true -> Index;
        false -> slices_index(T, Value, Index + 1)
    end.

% List implementation
-record(list, {head = null, tail = null}).

push(List = #list{tail = null}, Value) ->
    NewElement = {Value, null},
    List#list{head = NewElement, tail = NewElement};
push(List = #list{tail = Tail}, Value) ->
    NewElement = {Value, null},
    NewTail = setelement(2, Tail, NewElement),
    List#list{tail = NewElement}.

all_elements(#list{head = null}) ->
    [];
all_elements(#list{head = Head}) ->
    all_elements(Head, []).

all_elements({Value, null}, Acc) ->
    lists:reverse([Value|Acc]);
all_elements({Value, Next}, Acc) ->
    all_elements(Next, [Value|Acc]).

main() ->
    S = ["foo", "bar", "zoo"],
    io:format("index of zoo: ~p~n", [slices_index(S, "zoo")]),

    List = #list{},
    List1 = push(List, 10),
    List2 = push(List1, 13),
    List3 = push(List2, 23),
    io:format("list: ~p~n", [all_elements(List3)]).

In this Erlang version:

  1. We implement slices_index/2 as a recursive function that searches for an element in a list and returns its index.

  2. We create a list record to represent our linked list structure.

  3. The push/2 function adds elements to our list structure.

  4. all_elements/1 retrieves all elements from the list as a regular Erlang list.

  5. In the main/0 function, we demonstrate the usage of these functions.

To run the program, save it as generics.erl and use the Erlang shell:

$ erl
1> c(generics).
{ok,generics}
2> generics:main().
index of zoo: 2
list: [10,13,23]
3>

This Erlang implementation showcases similar functionality to the Go example, albeit without explicit generic types. Erlang’s dynamic typing allows us to work with different types without specifying them explicitly, which is somewhat similar to the flexibility provided by generics in statically-typed languages.