[fpc-devel] Looking for clarification on what I think are obviously missing "const" prefixes for parameters in the methods of TRect (the typshrdh.inc one)

Ben Grasset operator97 at gmail.com
Sun Jan 27 22:21:42 CET 2019


On Sun, Jan 27, 2019 at 8:00 AM Marco van de Voort <
fpc at pascalprogramming.org> wrote:

> I wonder though that maybe makes passing properties etc difficult?
>

As far I know "const" has no tangible effect on how properties can be
passed. Here's a little example to demonstrate:

program Test;

{$mode ObjFPC}{$H+}{$J-}
{$modeswitch AdvancedRecords}

type
  TRecA = record
  public
    A, B: SizeInt;
    constructor Create(const IA, IB: SizeInt);
    constructor Create(const ARec: TRecA);
  end;

  TRecB = record
  private
    FRecA: TRecA;
  public
    constructor Create(const ARec: TRecA);
    property RecA: TRecA read FRecA;
  end;

  TObjectB = object
  private
    FRecA: TRecA;
  public
    constructor Create(const ARec: TRecA);
    property RecA: TRecA read FRecA;
  end;

  TClassB = class
  private
    FRecA: TRecA;
  public
    constructor Create(const ARec: TRecA);
    property RecA: TRecA read FRecA;
  end;

  constructor TRecA.Create(const IA, IB: SizeInt);
  begin
    A := IA;
    B := IB;
  end;

  constructor TRecA.Create(const ARec: TRecA);
  begin
    A := ARec.A;
    B := ARec.B;
  end;

  constructor TRecB.Create(const ARec: TRecA);
  begin
    FRecA := ARec;
  end;

  constructor TObjectB.Create(const ARec: TRecA);
  begin
    FRecA := ARec;
  end;

  constructor TClassB.Create(const ARec: TRecA);
  begin
    FRecA := ARec;
  end;

var
  R: TRecB;
  O: TObjectB;
  C: TClassB;

begin
  R := TRecB.Create(TRecA.Create(5, 10));
  WriteLn(R.RecA.A, ' ', R.RecA.B);
  O.Create(R.RecA);
  WriteLn(O.RecA.A, ' ', O.RecA.B);
  C := TClassB.Create(O.RecA);
  WriteLn(C.RecA.A, ' ', C.RecA.B);
  R := TRecB.Create(C.RecA); //back to where we started...
  WriteLn(R.RecA.A, ' ', R.RecA.B);
  C.Free();
end.

Compiles without issues and works as intended. Personally though something
I often do is use static "class functions" instead of constructors for
advanced records, as they have the benefit of being able to be marked
inline as well as not having the "at least one parameter" restriction. From
an end-user perspective they're syntactically identical to how you'd call
an actual constructor, also, so there's no worries in that area either.

The program above changed in that fashion, where for example the TRecA
record is written like this:

type
  TRecA = record
  public
    A, B: SizeInt;
    class function Create(const IA, IB: SizeInt): TRecA; static; inline;
    class function Create(const ARec: TRecA): TRecA; static; inline;
  end;

  class function TRecA.Create(const IA, IB: SizeInt): TRec;
  begin
    with Result do begin
      A := IA;
      B := IB;
    end;
  end;

  class function TRecA.Create(const ARec: TRecA): TRec;
  begin
    with Result do begin
      A := ARec.A;
      B := ARec.B;
    end;
  end;

generates assembly at -O3 for the main method that is actually two lines
*shorter* than the assembly for the constructor version, while also of
course avoiding three entire function calls completely via inlining (both
TRecA constructors plus the one for TRecB.)

So I could change things in that regard too for TSize/TPoint/TRect while
I'm at it, unless anyone has any objections.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-devel/attachments/20190127/42604e0f/attachment.html>


More information about the fpc-devel mailing list