Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2026-10

Record Composition

5 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Mattias Gaertner

Hi all,

Thanks to Frederic Kehrein FPC main now supports Record Composition:

A record can now "contain" another record and have that record's members appear as its own.
Firstly this allows easy and automated conversion of C code, which uses anonymous structs and unions introduced in C11, into Pascal and to use C libraries frictionless and transparently through the same types and interfaces.
Secondly it allows for non trailing and multiple variant parts. And last but not least it can avoid {$IFDef} structures within the record definition allowing to reuse existing types.

The feature is enabled with

{$modeswitch RecordComposition}

It is not part of any mode by default.

Example:

------------------------
program demo;
{$mode objfpc}{$H+}
{$modeswitch advancedrecords}
{$modeswitch recordcomposition}
type
   TPoint = record
     X, Y: Integer;
     procedure Offset(dx, dy: Integer);
   end;
   TSize = record
     Width, Height: Integer;
     function Area: Integer;
   end;
   TRectangle = record
     contains TopLeft: TPoint;  // named composition
     contains TSize;            // unnamed composition
     function Right: Integer;
   end;
procedure TPoint.Offset(dx, dy: Integer);
begin
   Inc(X, dx);
   Inc(Y, dy);
end;
function TSize.Area: Integer;
begin
   Result := Width * Height;
end;
function TRectangle.Right: Integer;
begin
   Result := X + Width;   // composed members, no qualifier needed
end;
var
   r: TRectangle;
begin
   r.X := 10;             // same as r.TopLeft.X
   r.Y := 20;
   r.Width := 300;
   r.Height := 200;
   r.Offset(5, 5);        // calls TPoint.Offset with Self = r.TopLeft
   WriteLn(r.TopLeft.X, ' ', r.Right, ' ', r.Area);  // 15 315 60000
end.
------------------------

See here for the more information:
https://wiki.freepascal.org/FPC_New_Features_Trunk#Record_Composition

Mattias

Thomas Kurz
to Mattias Gaertner

I'm trying to use this feature, but I'm having some trouble:

All of my records contain a parameterless `class function Create: TWhateverRecord; static;`.

Now, when I try to contain one within the other, I'm stumbling across this compiler error:

Error: Overloaded identifier "CREATE" isn't a function

I guess this is because both records now have a `Create` function with the same signature. But how can I resolve that conflict?

And one more question: Does `Default(TComposedRecord)` correctly intialize the complete structure?

Kind regards,
Thomas

Earlier message 81 lines
----- Original Message ----- From: Mattias Gaertner via fpc-pascal To: Sent: Monday, October 19, 2026, 11:40:23 Subject: [fpc-pascal] Record Composition Hi all, Thanks to Frederic Kehrein FPC main now supports Record Composition: A record can now "contain" another record and have that record's members appear as its own. Firstly this allows easy and automated conversion of C code, which uses anonymous structs and unions introduced in C11, into Pascal and to use C libraries frictionless and transparently through the same types and interfaces. Secondly it allows for non trailing and multiple variant parts. And last but not least it can avoid {$IFDef} structures within the record definition allowing to reuse existing types. The feature is enabled with {$modeswitch RecordComposition} It is not part of any mode by default. Example: ------------------------ program demo; {$mode objfpc}{$H+} {$modeswitch advancedrecords} {$modeswitch recordcomposition} type TPoint = record X, Y: Integer; procedure Offset(dx, dy: Integer); end; TSize = record Width, Height: Integer; function Area: Integer; end; TRectangle = record contains TopLeft: TPoint; // named composition contains TSize; // unnamed composition function Right: Integer; end; procedure TPoint.Offset(dx, dy: Integer); begin Inc(X, dx); Inc(Y, dy); end; function TSize.Area: Integer; begin Result := Width * Height; end; function TRectangle.Right: Integer; begin Result := X + Width; // composed members, no qualifier needed end; var r: TRectangle; begin r.X := 10; // same as r.TopLeft.X r.Y := 20; r.Width := 300; r.Height := 200; r.Offset(5, 5); // calls TPoint.Offset with Self = r.TopLeft WriteLn(r.TopLeft.X, ' ', r.Right, ' ', r.Area); // 15 315 60000 end. ------------------------ See here for the more information: https://wiki.freepascal.org/FPC_New_Features_Trunk#Record_Composition Mattias
Michael Van Canneyt
to Thomas Kurz
Thomas Kurz wrote 9 lines
I'm trying to use this feature, but I'm having some trouble: All of my records contain a parameterless `class function Create: TWhateverRecord; static;`. Now, when I try to contain one within the other, I'm stumbling across this compiler error: Error: Overloaded identifier "CREATE" isn't a function I guess this is because both records now have a `Create` function with the same signature. But how can I resolve that conflict?

You cannot, it is a shortcoming of composed records. There is no way to distinguish between the various methods. Although the message needs improvement.

And one more question: Does `Default(TComposedRecord)` correctly intialize the complete structure?

Basically it does a fillchar(var,sizeOf(TComposedRecord),0), so that should be sufficient.

Michael.

Ondrej Pokorny
to Michael Van Canneyt
Michael Van Canneyt wrote 18 lines
On Thu, 22 Oct 2026, Thomas Kurz via fpc-pascal wrote: > I'm trying to use this feature, but I'm having some trouble: > > All of my records contain a parameterless `class function Create: > TWhateverRecord; static;`. > > Now, when I try to contain one within the other, I'm stumbling across > this compiler error: > > Error: Overloaded identifier "CREATE" isn't a function > > I guess this is because both records now have a `Create` function > with the same signature. But how can I resolve that conflict? You cannot, it is a shortcoming of composed records. There is no way to distinguish between the various methods. Although the message needs improvement.

I guess you can help yourself with a record helper:

TWhateverRecordHelper = record helper for TWhateverRecord
public
   class function Create: TWhateverRecord; static;
end;

Ondrej

Thomas Kurz
to Ondrej Pokorny
Show quoted text 6 lines
I guess you can help yourself with a record helper: TWhateverRecordHelper = record helper for TWhateverRecord public   class function Create: TWhateverRecord; static; end;

Thank you. This is very interesting, it is working indeed. Somehow fascinating.

Thomas