[fpc-pascal] Subclassing generic records?

Sven Barth pascaldragon at googlemail.com
Thu Jul 20 12:11:34 CEST 2017


On 17.07.2017 19:20, Ryan Joseph wrote:
> 
>> On Jul 17, 2017, at 10:58 AM, Sven Barth via fpc-pascal <fpc-pascal at lists.freepascal.org> wrote:
>>
>> I'll need to check whether Delphi allows that for helpers (doesn't matter whether the extended type is a specialization or not).
>>
>>
> 
> Thanks Sven. Records/objects/classes in Pascal feel very confused right now. Records are moving in the direction of legacy style “objects” which are allocated on the stack so I wonder why objects just don’t replace records already? Having said that why don’t classes just replace records/objects except they allocate on the stack? These 3 distinct constructs don’t really make sense more imo.

First of records can't replace objects, because objects have inheritance
and a VMT for virtual methods not to mention destructors. Secondly this
would lead to all kind of backwards compatibility problems.
Classes are not designed to be allocated on the stack. They are only on
the heap, thus they are a different kind of beast to records and objects.
And records - unlike objects and classes - can have operator overloads
*inside* of them which allows this operators to be used inside generic
specializations.

I have also another solution for your original problem. Take this code:

=== code begin ===

program trechelpfld;

{$mode objfpc}
{$modeswitch advancedrecords}

type
  TTest = record
    x, y: Double;
  end;

  TTestHelper = record helper for TTest
  private
    function GetWidth: Double; inline;
    function GetHeight: Double; inline;
    procedure SetWidth(aValue: Double); inline;
    procedure SetHeight(aValue: Double); inline;
  public
    property Width: Double read GetWidth write SetWidth;
    property Height: Double read GetHeight write SetHeight;
  end;

function TTestHelper.GetWidth: Double;
begin
  Result := x;
end;

function TTestHelper.GetHeight: Double;
begin
  Result := y;
end;

procedure TTestHelper.SetWidth(aValue: Double);
begin
  x := aValue;
end;

procedure TTestHelper.SetHeight(aValue: Double);
begin
  y := aValue;
end;

var
  t: TTest;
  x, y: Double;
begin
  t.x := 42.0;
  t.y := 21.0;

  x := t.Width;
  y := t.Height;

  t.Width := y;
  t.Height := x;
end.

=== code end ===

Through the use of "inline" this results in code without calls as the
assembly output of the main procedure without any optimizations shows:

=== code begin ===

.section .text.n_main
        .balign 16,0x90
.globl  PASCALMAIN
        .type   PASCALMAIN, at function
PASCALMAIN:
.globl  main
        .type   main, at function
main:
.Lc21:
# Temps allocated between rbp-16 and rbp+0
# [45] begin
        pushq   %rbp
.Lc23:
.Lc24:
        movq    %rsp,%rbp
.Lc25:
        leaq    -16(%rsp),%rsp
        call    FPC_INITIALIZEUNITS
# [46] t.x := 42.0;
        movq    _$TRECHELPFLD$_Ld1,%rax
        movq    %rax,U_$P$TRECHELPFLD_$$_T
# [47] t.y := 21.0;
        movq    _$TRECHELPFLD$_Ld2,%rax
        movq    %rax,U_$P$TRECHELPFLD_$$_T+8
# [49] x := t.Width;
        movsd   U_$P$TRECHELPFLD_$$_T,%xmm0
        movsd   %xmm0,U_$P$TRECHELPFLD_$$_X
# [50] y := t.Height;
        movsd   U_$P$TRECHELPFLD_$$_T+8,%xmm0
        movsd   %xmm0,U_$P$TRECHELPFLD_$$_Y
# [52] t.Width := y;
        movq    U_$P$TRECHELPFLD_$$_Y,%rax
        movq    %rax,U_$P$TRECHELPFLD_$$_T
# [53] t.Height := x;
        movq    U_$P$TRECHELPFLD_$$_X,%rax
        movq    %rax,U_$P$TRECHELPFLD_$$_T+8
# [54] end.
        call    FPC_DO_EXIT
        leave
        ret
.Lc22:
.Le4:
        .size   main, .Le4 - main

=== code end ===

It might be more to write, but it works...

Regards,
Sven



More information about the fpc-pascal mailing list