Jump to content
Bernard

Record Circular References

Recommended Posts

3 minutes ago, Bernard said:

Is this different than Classes with forward declarations?

Classes are reference types.

Share this post


Link to post
1 hour ago, Anders Melander said:

Classes are reference types.

I get it now.

Share this post


Link to post
11 hours ago, Bernard said:

Is this different than Classes with forward declarations?

Classes are reference types in Delphi:

 

"Reference types can be forward declared because their size are always known (=SizeOf(pointer))."

Share this post


Link to post

If size was the only problem, I can imagine something like this ("human preprocessor"):


 

type

 tRecordA = record of size 8;

 tRecordB = record
  ...
  function Test: tRecordA;
 end;

 tRecordA = record
  x, y: integer;
 end;

 

Share this post


Link to post
5 hours ago, Vandrovnik said:

If size was the only problem

It isn't. The type and offset of the members needs to be known too:

type
  TMyRecord = record
    Foo: integer;
    Bar: string;
  end;

  TMyClass = class
  private
    FFooBar: TMyRecord;
  public
    property Foo: integer read FFooBar.Foo;
    property Bar: string read FFooBar.Bar;
  end;

 

Share this post


Link to post
55 minutes ago, Anders Melander said:

It isn't. The type and offset of the members needs to be known too:


type
  TMyRecord = record
    Foo: integer;
    Bar: string;
  end;

  TMyClass = class
  private
    FFooBar: TMyRecord;
  public
    property Foo: integer read FFooBar.Foo;
    property Bar: string read FFooBar.Bar;
  end;

 

If what you say were true, then class forward references would not exist.

Share this post


Link to post
12 minutes ago, David Heffernan said:

If what you say were true, then class forward references would not exist.

I believe Anders is right.

Class reference is just a pointer - its size is known. When you use this class as a member of another class (fChild: tChild, where tChild is a class), you cannot reference its members in properties (property x: integer read fChild.x). If fChild is a record (fChild: tChild, where tChild is a record), you can reference its members in properties, like in Anders' example (property x: integer read fChild.x).

Share this post


Link to post
33 minutes ago, Vandrovnik said:

I believe Anders is right.

Class reference is just a pointer - its size is known. When you use this class as a member of another class (fChild: tChild, where tChild is a class), you cannot reference its members in properties (property x: integer read fChild.x). If fChild is a record (fChild: tChild, where tChild is a record), you can reference its members in properties, like in Anders' example (property x: integer read fChild.x).

Not being able to do that one thing would hardly invalidate the entire enterprise. We'd still be able to use the type as procedure argument which is the main thing we are striving for. 

 

But the whole argument is predicted on this single pass. It's no big deal to pass over each type section twice to process forward declarations. Won't make a blind bit of difference to performance. 

 

Bottom line is that it is perfectly possible to do this if Emba wanted to. 

Share this post


Link to post
2 hours ago, David Heffernan said:

Won't make a blind bit of difference to performance.

Not in this single case, I agree, but beware of tunnel vision. Regardless the obstacle is probably more a question of resources and priorities.

It might also not be easy to shoehorn something like this into the existing compiler. If it's implemented like a traditional one-pass compiler it will be using various optimizations that can only be made because it's a one-pass compiler.

Share this post


Link to post
11 minutes ago, Anders Melander said:

Regardless the obstacle is probably more a question of resources and priorities.

This is the point that I've been making all along. 

  • Like 1

Share this post


Link to post

I certainly understand that many people did not program on a pure Pascal.
Use pointers and you will be happy.

 

Pointers to a record can be declared before the record is declared.

Also if you pass a record as a parameter,
there is no need to pass the value as it is extremely inefficient and the recording value is copied to the stack.
Transmit the record by var or by const.

 

PPoint2D = ^tPoint2D;


 

Share this post


Link to post
On 5/13/2020 at 8:16 PM, Bernard said:

It would be great with all the record enhancements in the next version to be able to write

 

tPoint2D = record;

 

  tPolar2D = record
    Radius: Double;
    azimuth: Double;
    function ToCartesian: tPoint2D;
  end;

 

  tPoint2D = record
    x: Double;
    y: Double;
    function ToPolar: tPolar2D;
  end;

 

Thanks again for the feedback

PPoint2D = ^TPoint2D;
PPolar2D = ^TPolar2D;

constructor TPolar2D.From(const Pt: PPoint2D);
constructor TPolar2D.From(X, Y: Double);

constructor TPoint2D.From(const Pt: PPolar2D);
constructor TPoint2D.From(Radius, Azimuth: Double);

PNode = ^TNode;
TNode = record
  next: PNode;
end;

var 
  ppt: TPolar2D;
  cpt: TPoint2D;
begin
  ppt := TPolar2D.From(@cpt);
end.

 

Edited by Marat1961

Share this post


Link to post
On 5/13/2020 at 3:16 PM, Bernard said:

It would be great with all the record enhancements in the next version to be able to write

 

tPoint2D = record;

 

  tPolar2D = record
    Radius: Double;
    azimuth: Double;
    function ToCartesian: tPoint2D;
  end;

 

  tPoint2D = record
    x: Double;
    y: Double;
    function ToPolar: tPolar2D;
  end;

 

One possible solution could be allowing a two-phase declaration:

 

  tPolar2D = record
    Radius: Double;
    azimuth: Double;
  end; forward; //keyword just to say there are methods to be defined later

 

  tPoint2D = record
    x: Double;
    y: Double;
    function ToPolar: tPolar2D;
  end;

 

  tPolar2D = record finalization
    function ToCartesian: tPoint2D;
  end;

Share this post


Link to post
  tPolar2D = record
    Radius: Double;
    azimuth: Double;
  end; forward; //keyword just to say there are methods to be defined later

In my opinion, this is not the most successful design.
A radical solution is needed.
It is much better to add a namespace.
And inside the namespace, allow to refer to any declarations, regardless of the order of their declaration.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×