Generics in Pascal

program Generics;

uses
  SysUtils, Generics.Collections;

type
  TComparable = record
  end;

  TSlicesIndex<S: array of E; E: TComparable> = class
    class function Execute(const s: S; const v: E): Integer;
  end;

  TList<T> = class
  private
    type
      TElement = class
        Next: TElement;
        Value: T;
      end;
  private
    FHead, FTail: TElement;
  public
    procedure Push(const v: T);
    function AllElements: TArray<T>;
  end;

class function TSlicesIndex<S, E>.Execute(const s: S; const v: E): Integer;
var
  i: Integer;
begin
  for i := Low(s) to High(s) do
    if s[i] = v then
      Exit(i);
  Result := -1;
end;

procedure TList<T>.Push(const v: T);
var
  NewElement: TElement;
begin
  NewElement := TElement.Create;
  NewElement.Value := v;
  
  if FTail = nil then
  begin
    FHead := NewElement;
    FTail := NewElement;
  end
  else
  begin
    FTail.Next := NewElement;
    FTail := NewElement;
  end;
end;

function TList<T>.AllElements: TArray<T>;
var
  e: TElement;
  List: TList<T>;
begin
  List := TList<T>.Create;
  try
    e := FHead;
    while e <> nil do
    begin
      List.Add(e.Value);
      e := e.Next;
    end;
    Result := List.ToArray;
  finally
    List.Free;
  end;
end;

var
  s: TArray<string>;
  IntList: TList<Integer>;

begin
  s := TArray<string>.Create('foo', 'bar', 'zoo');

  WriteLn('index of zoo: ', TSlicesIndex<TArray<string>, string>.Execute(s, 'zoo'));

  IntList := TList<Integer>.Create;
  try
    IntList.Push(10);
    IntList.Push(13);
    IntList.Push(23);
    WriteLn('list: ', String.Join(', ', IntList.AllElements));
  finally
    IntList.Free;
  end;
end.

This Pascal code demonstrates the concept of generics, which is similar to the original example. Here’s an explanation of the key parts:

  1. We define a TSlicesIndex generic class with a static Execute method, which is similar to the SlicesIndex function in the original example. It takes a generic array and a value, and returns the index of the first occurrence of the value in the array.

  2. We define a generic TList class, which implements a singly-linked list. It has methods for pushing elements and retrieving all elements as an array.

  3. The Push method adds elements to the list, similar to the original example.

  4. The AllElements method returns all elements of the list as an array.

  5. In the main program, we demonstrate the use of these generic types and methods:

    • We create an array of strings and use TSlicesIndex to find the index of “zoo”.
    • We create a TList<Integer>, add some integers to it, and then print all elements.

Note that Pascal’s generics syntax is different from Go’s. Instead of square brackets, Pascal uses angle brackets for generic type parameters. Also, Pascal doesn’t have a direct equivalent of Go’s ~ operator for type constraints, so we’ve simplified this aspect in the translation.

To run this program, you would typically save it as a .pas file and compile it with a Pascal compiler that supports generics, such as Free Pascal or Delphi.

$ fpc generics.pas
$ ./generics
index of zoo: 2
list: 10, 13, 23

This example demonstrates how generics can be used in Pascal to write flexible, type-safe code that works with different data types.