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;
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;
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:
Runtime VMT dispatch — when you read or write
B.Value, the runtime resolvesGetValue/SetValuethrough the virtual method table, not by treating the property name as a field lookup.Semantic relaxation for backing fields — fields named
F*referenced insideTClasse::Metodoimplementations 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.
Run it with:
crab-pascal run tests/fixtures/property_accessor_methods.pas
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;
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;
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:
Dispatch VMT no runtime — ao ler ou escrever
B.Value, o runtime resolveGetValue/SetValuepela virtual method table, não tratando o nome da property como lookup de field.Relaxamento semântico para backing fields — fields
F*referenciados dentro de implementaçõesTClasse::Metodonã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.
Execute com:
crab-pascal run tests/fixtures/property_accessor_methods.pas
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,defaulte 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)