DEV Community

CrabPascal
CrabPascal

Posted on

Generics in CrabPascal: TList and TDictionary (v2.15.0) | Generics no CrabPascal: TList e TDictionary (v2.15.0)

Bilingual post · Post bilíngue

Jump to: English · Português


English {#english}

Generics in CrabPascal: TList and TDictionary (v2.15.0)

Generic collections are the backbone of modern Delphi — caches, registries, JSON maps. Sprint 7 (v2.15.0) shipped System.Generics.Collections with working TDictionary<K,V> and TList<T>, including the all-important TryGetValue with var parameters.

Dictionary basics

program DictDemo;
uses
  System.SysUtils,
  System.Generics.Collections;

var
  D: TDictionary<string, Integer>;
  V: Integer;
begin
  D := TDictionary<string, Integer>.Create;
  try
    D.Add('apples', 3);
    D.Add('oranges', 5);

    if D.TryGetValue('apples', V) then
      WriteLn('apples = ', V)
    else
      WriteLn('not found');
  finally
    D.Free;
  end;
end.
Enter fullscreen mode Exit fullscreen mode

TryGetValue writes into V only when the key exists — the Delphi pattern you expect in production code.

Why var mattered in Sprint 7

Before v2.15.0, var parameters were incomplete. TryGetValue needs write-back semantics: the callee mutates the caller's variable through a reference. CrabPascal introduced Value::Reference and write-back in procedure dispatch specifically for this API surface.

cargo test --test generics_collections
Enter fullscreen mode Exit fullscreen mode

Parser and type syntax

Instantiated generics in expressions now parse cleanly:

D := TDictionary<string, Integer>.Create;
L := TList<string>.Create;
Enter fullscreen mode Exit fullscreen mode

The semantic layer recognizes Generics.Collections when you uses System.Generics.Collections. Method dispatch routes Add, TryGetValue, and Create through intrinsics before empty VMT lookups fail.

TList quick example

var
  L: TList<string>;
begin
  L := TList<string>.Create;
  try
    L.Add('alpha');
    L.Add('beta');
    WriteLn('Count = ', L.Count);
  finally
    L.Free;
  end;
end;
Enter fullscreen mode Exit fullscreen mode

Full TList feature parity (sorting, binary search) evolves in later releases; Sprint 7 nailed construction, Add, Count, and TryGetValue.

Assignment normalization

A implementation detail worth knowing: assignments like D := TDictionary<...>.Create required normalize_call_name in execute_assignment, not only in direct calls. Without that fix, generics looked fine in check but failed mysteriously at runtime.

Real-world use: HTTP handlers

Horse handlers often build response maps:

// simplified pattern
var
  Cache: TDictionary<string, string>;
begin
  Cache := TDictionary<string, string>.Create;
  try
    Cache.Add('Content-Type', 'application/json');
    // ...
  finally
    Cache.Free;
  end;
end;
Enter fullscreen mode Exit fullscreen mode

What's still evolving

Explicit out parameters in the parser, advanced collection algorithms, and full build-exe codegen for generic dispatch were tracked as debt. For learning and API prototyping, v2.15.0 is the sprint where CrabPascal stops telling you to use TStringList as a fake hash map.

Run check, then run, then parity tests when shipping binaries. Generics are the bridge between Pascal nostalgia and code you would write in Delphi 12 today.


Português {#portugus}

Generics no CrabPascal: TList e TDictionary (v2.15.0)

Coleções genéricas são a espinha dorsal do Delphi moderno — caches, registros, mapas JSON. A Sprint 7 (v2.15.0) entregou System.Generics.Collections com TDictionary<K,V> e TList<T> funcionais, incluindo o indispensável TryGetValue com parâmetros var.

Básico de dictionary

program DictDemo;
uses
  System.SysUtils,
  System.Generics.Collections;

var
  D: TDictionary<string, Integer>;
  V: Integer;
begin
  D := TDictionary<string, Integer>.Create;
  try
    D.Add('apples', 3);
    D.Add('oranges', 5);

    if D.TryGetValue('apples', V) then
      WriteLn('apples = ', V)
    else
      WriteLn('not found');
  finally
    D.Free;
  end;
end.
Enter fullscreen mode Exit fullscreen mode

TryGetValue escreve em V só quando a chave existe — o padrão Delphi que você espera em produção.

Por que var importou na Sprint 7

Antes da v2.15.0, parâmetros var estavam incompletos. TryGetValue precisa de write-back: o callee muta a variável do caller via referência. O CrabPascal introduziu Value::Reference e write-back no dispatch de procedures especificamente para essa superfície de API.

cargo test --test generics_collections
Enter fullscreen mode Exit fullscreen mode

Parser e sintaxe de tipos

Genéricos instanciados em expressões agora parseiam limpo:

D := TDictionary<string, Integer>.Create;
L := TList<string>.Create;
Enter fullscreen mode Exit fullscreen mode

A camada semântica reconhece Generics.Collections ao fazer uses System.Generics.Collections. Dispatch de métodos roteia Add, TryGetValue e Create por intrinsics antes de lookups VMT vazios falharem.

Exemplo rápido com TList

var
  L: TList<string>;
begin
  L := TList<string>.Create;
  try
    L.Add('alpha');
    L.Add('beta');
    WriteLn('Count = ', L.Count);
  finally
    L.Free;
  end;
end;
Enter fullscreen mode Exit fullscreen mode

Paridade completa de TList (sort, busca binária) evolui em releases posteriores; a Sprint 7 acertou construção, Add, Count e TryGetValue.

Normalização em assignment

Detalhe de implementação: assignments como D := TDictionary<...>.Create exigiram normalize_call_name em execute_assignment, não só em chamadas diretas. Sem esse fix, genéricos passavam no check mas falhavam misteriosamente em runtime.

Uso real: handlers HTTP

Handlers Horse frequentemente montam mapas de resposta:

// padrão simplificado
var
  Cache: TDictionary<string, string>;
begin
  Cache := TDictionary<string, string>.Create;
  try
    Cache.Add('Content-Type', 'application/json');
    // ...
  finally
    Cache.Free;
  end;
end;
Enter fullscreen mode Exit fullscreen mode

O que ainda evolui

Parâmetros out explícitos no parser, algoritmos avançados de coleção e codegen build-exe completo para dispatch genérico ficaram como débito. Para aprendizado e prototipagem de API, a v2.15.0 é a sprint em que o CrabPascal para de pedir TStringList como hash map falso.

Rode check, depois run, depois testes de paridade ao entregar binários. Generics são a ponte entre nostalgia Pascal e código que você escreveria no Delphi 12 hoje.


Published on dev.to/@crabpascal · Código em CrabPascal

Top comments (0)