Subclassing generic records?

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Subclassing generic records?

Ryan Joseph
I’m trying to find a way to extend generic records since (as far as I know) there is no subclassing of records. I could use variant records here but these don’t work with generics so I tried record helpers and properties to basically rename the x/y variables in TVec2 but I get errors on the width/height properties. Is there a workaround for this?

type
        generic TVec2<T> = record
                public
                        x, y: T;
        end;
type
        TSize = specialize TVec2<TFloat>;
type
        TVec2Size = record helper for TSize
                property Width: TFloat read x write x;
                property Height: TFloat read y write y;
        end;


Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Subclassing generic records?

Free Pascal - General mailing list

Am 17.07.2017 18:24 schrieb "Ryan Joseph" <[hidden email]>:
>
> I’m trying to find a way to extend generic records since (as far as I know) there is no subclassing of records. I could use variant records here but these don’t work with generics so I tried record helpers and properties to basically rename the x/y variables in TVec2 but I get errors on the width/height properties. Is there a workaround for this?
>
> type
>         generic TVec2<T> = record
>                 public
>                         x, y: T;
>         end;
> type
>         TSize = specialize TVec2<TFloat>;
> type
>         TVec2Size = record helper for TSize
>                 property Width: TFloat read x write x;
>                 property Height: TFloat read y write y;
>         end;

I'll need to check whether Delphi allows that for helpers (doesn't matter whether the extended type is a specialization or not).

Regards,
Sven


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Subclassing generic records?

Ryan Joseph

> On Jul 17, 2017, at 10:58 AM, Sven Barth via fpc-pascal <[hidden email]> 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.

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Subclassing generic records?

Free Pascal - General mailing list
On 17.07.2017 19:20, Ryan Joseph wrote:
>
>> On Jul 17, 2017, at 10:58 AM, Sven Barth via fpc-pascal <[hidden email]> 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,@function
PASCALMAIN:
.globl  main
        .type   main,@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
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Subclassing generic records?

Ryan Joseph
Thanks Sven, that’s one way around it.

So is it by design that records don’t have inheritance or is this planned?

and is it also by design that classes don’t allow operator overloads inside them? That seems like an omission since the way they’re implemented in records is much nicer imo.

> On Jul 20, 2017, at 4:11 AM, Sven Barth via fpc-pascal <[hidden email]> wrote:
>
> I have also another solution for your original problem. Take this code:

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Subclassing generic records?

Free Pascal - General mailing list

Am 21.07.2017 23:36 schrieb "Ryan Joseph" <[hidden email]>:
>
> Thanks Sven, that’s one way around it.
>
> So is it by design that records don’t have inheritance or is this planned?

Yes, that's by design and there are no plans to change this.

> and is it also by design that classes don’t allow operator overloads inside them? That seems like an omission since the way they’re implemented in records is much nicer imo.

There are two points you need to be aware of to understand why thinks are the way they are:
First of global operator overloads were the first that were implemented in FPC. Then Delphi came along and added record operator overloads, because they needed them for generics. FPC followed, cause the global overloads are useless in that case.
Secondly even for global operator overloads classes are not really that suitable, cause in complex expressions (let's say "a * (b + c)") you'll have the generation of temporary variables (in the example the result of "b + c"), but the compiler can't know whether it's really a temporary value that it can free after the whole expression is handled or whether merely the instance that had been passed in (let's say "b") had been modified and passed as a result. Thus operator overloads for classes can easily lead to memory leaks or other hard to debug problems. Yes, that's already possible with global operators as well, but with operators that are part of the class that would be much more inviting.

Regards,
Sven


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Subclassing generic records?

Martin Schreiber-2
In reply to this post by Ryan Joseph
On Friday 21 July 2017 23:04:20 Ryan Joseph wrote:
> Thanks Sven, that’s one way around it.
>
> So is it by design that records don’t have inheritance or is this planned?
>
MSElang has a concept of unified record, object and class constructs. There a
record is a simplified object which never has a VMT and has no methods. An
object has a VMT only if the attribute [virtual] is given. An object can be
instantiated in global or stack memory or on heap if it has a constructor()
and destructor().
A class is an object which always is instantiated on heap and which provides
implicit dereferencing. Classes can inherit from objects.
https://gitlab.com/mseide-msegui/mselang/wikis/home/mselang_objects
https://gitlab.com/mseide-msegui/mselang/wikis/home
(under construction).

Martin
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Loading...