DEV Community

CrabPascal
CrabPascal

Posted on

Method-Based Properties in CrabPascal | Properties por método no CrabPascal

Bilingual post · Post bilíngue

Jump to: English · Português


English {#english}

Method-Based Properties in CrabPascal

Delphi properties are not just syntactic sugar for fields. Many real classes expose computed values, validate assignments, or trigger side effects through accessor methods. CrabPascal v2.20.0 (Sprint 12) closes an important gap: properties with read/write backed by methods now work in the run runtime via VMT dispatch.

Field-backed vs method-backed

The simplest property maps directly to a field:

type
  TCounter = class
  private
    FCount: Integer;
  public
    property Count: Integer read FCount write FCount;
  end;
Enter fullscreen mode Exit fullscreen mode

Method-backed properties delegate to functions and procedures:

type
  TBox = class
  private
    FValue: Integer;
    function GetValue: Integer;
    procedure SetValue(var V: Integer);
  public
    property Value: Integer read GetValue write SetValue;
  end;
Enter fullscreen mode Exit fullscreen mode

This pattern appears in VCL components, REST DTOs, and service layers. Without it, porting even moderate Delphi code fails early.

How Sprint 12 fixed it

Two changes landed together:

  1. Runtime VMT dispatch — when you read or write B.Value, the runtime resolves GetValue / SetValue through the virtual method table, not by treating the property name as a field lookup.

  2. Semantic relaxation for backing fields — fields named F* referenced inside TClasse::Metodo implementations no longer trigger false errors. Accessor methods almost always touch private backing fields; blocking that broke legitimate code.

Canonical fixture

The repo ships a focused test program:

function TBox.GetValue: Integer;
begin
  Result := FValue;
end;

procedure TBox.SetValue(var V: Integer);
begin
  FValue := V;
end;

var
  B: TBox;
  X: Integer;
begin
  B := TBox.Create;
  X := 42;
  B.Value := X;
  WriteLn(B.Value);  // prints 42
end.
Enter fullscreen mode Exit fullscreen mode

Run it with:

crab-pascal run tests/fixtures/property_accessor_methods.pas
Enter fullscreen mode Exit fullscreen mode

Automated coverage lives in tests/properties_runtime.rs.

Design note: var on setters

Delphi setter procedures often take the new value as a var parameter when they swap or normalize in place. CrabPascal's current runtime mirrors enough of that calling convention for common patterns. Exotic setter signatures may still need follow-up sprints.

What is still pending

  • Indexed properties (property Items[Index: Integer]: T read GetItem write SetItem)
  • Array default properties (property X[Index: Integer])
  • stored, default, and visibility edge cases

Sprint 12 intentionally scoped to the 80/20 case: single-value properties with method accessors used across Horse examples and CRUD services.

Try it in your project

If a Delphi class compiles but property access fails at runtime, check whether accessors are methods. Update to v2.20.0+ and re-run with crab-pascal check then crab-pascal run. Report remaining gaps on Dev.to @crabpascal or Bitbucket issues — we add fixtures for each confirmed bug.


Português {#portugus}

Properties por método no CrabPascal

Properties Delphi não são só açúcar sintático para fields. Muitas classes reais expõem valores calculados, validam atribuições ou disparam efeitos colaterais via métodos accessor. O CrabPascal v2.20.0 (Sprint 12) fecha uma lacuna importante: properties com read/write por método agora funcionam no runtime run via dispatch VMT.

Field vs método

A property mais simples mapeia direto para um field:

type
  TCounter = class
  private
    FCount: Integer;
  public
    property Count: Integer read FCount write FCount;
  end;
Enter fullscreen mode Exit fullscreen mode

Properties por método delegam para functions e procedures:

type
  TBox = class
  private
    FValue: Integer;
    function GetValue: Integer;
    procedure SetValue(var V: Integer);
  public
    property Value: Integer read GetValue write SetValue;
  end;
Enter fullscreen mode Exit fullscreen mode

Esse padrão aparece em componentes VCL, DTOs REST e camadas de serviço. Sem ele, portar código Delphi moderado falha cedo.

O que o Sprint 12 corrigiu

Duas mudanças chegaram juntas:

  1. Dispatch VMT no runtime — ao ler ou escrever B.Value, o runtime resolve GetValue / SetValue pela virtual method table, não tratando o nome da property como lookup de field.

  2. Relaxamento semântico para backing fields — fields F* referenciados dentro de implementações TClasse::Metodo não disparam mais falsos erros. Accessors quase sempre tocam fields privados; bloquear isso quebrava código legítimo.

Fixture canônico

O repositório inclui um programa de teste focado:

function TBox.GetValue: Integer;
begin
  Result := FValue;
end;

procedure TBox.SetValue(var V: Integer);
begin
  FValue := V;
end;

var
  B: TBox;
  X: Integer;
begin
  B := TBox.Create;
  X := 42;
  B.Value := X;
  WriteLn(B.Value);  // imprime 42
end.
Enter fullscreen mode Exit fullscreen mode

Execute com:

crab-pascal run tests/fixtures/property_accessor_methods.pas
Enter fullscreen mode Exit fullscreen mode

Cobertura automatizada em tests/properties_runtime.rs.

Nota de design: var em setters

Setters Delphi frequentemente recebem o novo valor como parâmetro var quando fazem swap ou normalização in-place. O runtime atual do CrabPascal espelha convenção de chamada suficiente para padrões comuns. Assinaturas exóticas podem precisar de sprints futuros.

O que ainda falta

  • Properties indexadas (property Items[Index: Integer]: T read GetItem write SetItem)
  • Default array properties
  • stored, default e casos de visibilidade

O Sprint 12 focou no caso 80/20: properties de valor único com accessors por método, usadas nos exemplos Horse e CRUD.

Teste no seu projeto

Se uma classe Delphi compila mas o acesso à property falha em runtime, verifique se os accessors são métodos. Atualize para v2.20.0+ e rode crab-pascal check depois crab-pascal run. Reporte lacunas no Dev.to @crabpascal ou issues no Bitbucket — adicionamos fixture para cada bug confirmado.


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

Top comments (0)