Jump to content
Bernard

Record Circular References

Recommended Posts

Hi All,

 

Is there a better way of doing the following, getting rid of the tPolarHelper, without changing to classes.

 

  tPolar2D = record
    Radius: Double;
    azimuth: Double;
  end;

 

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

 

  tPolarHelper = record helper for tPolar2D
    function ToCartesian: tPoint2D;
  end;

 

I know if the above were classes then I could write

 

  tPoint2D = class;

 

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

 

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

 

Thanks.

Share this post


Link to post

What about operators:

  tPoint2D = record
    x: Double;
    y: Double;
    class function Implicit(A: tPoint2D): tPolar2d;
    class function Implicit(A: tPolar2D): tPoint2D;
  end;

 

Edited by Uwe Raabe

Share this post


Link to post

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

Share this post


Link to post
28 minutes ago, 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

Bloody annoying that this can't be done

  • Like 3

Share this post


Link to post
2 hours ago, Uwe Raabe said:

What about operators:


  tPoint2D = record
    x: Double;
    y: Double;
    class function Implicit(A: tPoint2D): tPolar2d;
    class function Implicit(A: tPolar2D): tPoint2D;
  end;

 

Does this get rid of the Circular reference issue?

 

I have always found it starange that records have class functions instead of record functions.

 

Feels funny naming a record function a class function.

 

Its like when one of my young kids calls a poo a pee.  I know that they were trying to say 🙂

Share this post


Link to post
1 hour ago, Bernard said:

Does this get rid of the Circular reference issue?

Yes, because the reference to tPolar2D is only inside tPoint2D, which still has to be declared after tPolar2D.

 

The benefit of the operators is the ease of conversion by assignment. This is the (corrected) declaration with some example assignments (TBD: calculations):

 

type
  tPolar2D = record
    Radius: Double;
    azimuth: Double;
  end;

type
  tPoint2D = record
    x: Double;
    y: Double;
  public
    class operator Implicit(A: tPoint2D): tPolar2d; overload;
    class operator Implicit(A: tPolar2D): tPoint2D; overload;
  end;

class operator tPoint2D.Implicit(A: tPoint2D): tPolar2d;
begin
  Result.Radius := ...
  Result.azimuth := ...
end;

class operator tPoint2D.Implicit(A: tPolar2D): tPoint2D;
begin
  Result.x := ...
  Result.y := ...
end;

var
  cart: tPoint2D;
  pol: tPolar2D;
begin
  cart := pol;
  pol := cart;
end.

 

  • Like 2

Share this post


Link to post
4 hours ago, Bernard said:

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

Not going to happen.  You can't forward-declare records.

Share this post


Link to post
2 hours ago, Remy Lebeau said:

Not going to happen.  You can't forward-declare records.

You should be able to forward declare their methods. No reason not to be able to do that. 

Share this post


Link to post
55 minutes ago, David Heffernan said:

No reason not to be able to do that.

Without access to the compiler source it's hard to tell, but I'll bet there are some.
For one, as far as I can tell, it would require forward declaration of the record and I know there are good reasons why that isn't possible.

How would you envision forward declaration of a record method would look?

Share this post


Link to post
10 minutes ago, Anders Melander said:

Without access to the compiler source it's hard to tell, but I'll bet there are some.
For one, as far as I can tell, it would require forward declaration of the record and I know there are good reasons why that isn't possible.

How would you envision forward declaration of a record method would look?

The argument is that its a single pass compile. So make it two pass. Simples. 

  • Like 1
  • Haha 1

Share this post


Link to post
1 hour ago, David Heffernan said:

So make it two pass. Simples. 

Yeah, THAT is not going to happen anytime soon, either.

Share this post


Link to post
7 minutes ago, Remy Lebeau said:

Yeah, THAT is not going to happen anytime soon, either.

Well no, of course not. So we are stuck with this second rate language. 

Share this post


Link to post
9 hours ago, Uwe Raabe said:

Yes, because the reference to tPolar2D is only inside tPoint2D, which still has to be declared after tPolar2D.

 

The benefit of the operators is the ease of conversion by assignment. This is the (corrected) declaration with some example assignments (TBD: calculations):

 

The class operators for records with calculations that fit my example are a great solution for this issue.

 

Thanks for that.  

 

 

Share this post


Link to post
4 hours ago, Anders Melander said:

Without access to the compiler source it's hard to tell, but I'll bet there are some.
For one, as far as I can tell, it would require forward declaration of the record and I know there are good reasons why that isn't possible.

How would you envision forward declaration of a record method would look?

Could you elaborate on why it is not possible? 

 

Share this post


Link to post
3 hours ago, Bernard said:

Could you elaborate on why it is not possible? 

 

It is possible. Plenty of languages can handle this. Emba could implement it if they chose to. 

Share this post


Link to post
7 hours ago, David Heffernan said:

Well no, of course not. So we are stuck with this second rate language. 

A second rate language that compiles fast as hell...at least for Windows. Now I wonder why  😉

  • Like 1

Share this post


Link to post
53 minutes ago, Sherlock said:

A second rate language that compiles fast as hell...at least for Windows. Now I wonder why  😉

C# compilation is pretty darn fast. Delphi compilation for 64 bit on Windows is not exactly fast.

 

I'm sure that a first pass to define record type layouts followed by a second pass for everything else would not be costly.

 

This isn't going to be about compilation speedy. It's about the pain of refactoring the front end. 

  • Like 2

Share this post


Link to post
8 hours ago, David Heffernan said:

So we are stuck with this second rate language.

You are not stuck. There's always choice.

I'm assuming you've chosen to stick with Delphi because you like the language. With the benefits Delphi provides comes some limitations. That's just part of the equation.

 

 

4 hours ago, Bernard said:

Could you elaborate on why it is not possible? 

Because it's a one-pass compiler (mostly). The benefit is that it is fast. The price is that there are some things that are not possible.

Reference types can be forward declared because their size are always known (=SizeOf(pointer)). The size of record types are not known until they have been fully declared. This means that the compiler cannot determine the layout of a record type if it contains other record types that have not been fully declared, and it needs to know the layout in order to generate the code that uses it.

This problem can be solved, with certain limitations, while still staying a one-pass compiler, but at a cost of added complexity in the compiler and longer compile time.

Share this post


Link to post
4 minutes ago, David Heffernan said:

I'm sure that a first pass to define record type layouts followed by a second pass for everything else would not be costly.

Something like a record helper 🙂

I always wonder why there can be just one class/record helper...

Share this post


Link to post
4 minutes ago, David Heffernan said:

This isn't going to be about compilation speedy. It's about the pain of refactoring the front end. 

Yes, probably although I don't think the front end is enough.

But more importantly I think it's about cost/benefit and the limited resources available to them.

Share this post


Link to post
20 minutes ago, Anders Melander said:

You are not stuck.

With over a million lines of code, it's an epic task to migrate. 

 

22 minutes ago, Anders Melander said:

This problem can be solved, with certain limitations, while still staying a one-pass compiler, but at a cost of added complexity in the compiler and longer compile time.

I can't believe that the increase in compiler time would be significant. 

  • Like 1

Share this post


Link to post
4 hours ago, Anders Melander said:

Because it's a one-pass compiler (mostly). The benefit is that it is fast. The price is that there are some things that are not possible.

Reference types can be forward declared because their size are always known (=SizeOf(pointer)). The size of record types are not known until they have been fully declared. This means that the compiler cannot determine the layout of a record type if it contains other record types that have not been fully declared, and it needs to know the layout in order to generate the code that uses it.

This problem can be solved, with certain limitations, while still staying a one-pass compiler, but at a cost of added complexity in the compiler and longer compile time.

I wonder if the solution could be a post processor that processed the forward declarations and created a helper file for the compiler to use during compilation time.  Now the compiler could remain a single pass.

 

Share this post


Link to post
11 hours ago, Bernard said:

I wonder if the solution could be a post processor that processed the forward declarations and created a helper file for the compiler to use during compilation time.  Now the compiler could remain a single pass.

You mean a preprocessor.

Adding a preprocessor would amount to the same as making the compiler multi-pass.

Share this post


Link to post
On 5/14/2020 at 8:08 AM, Anders Melander said:

Because it's a one-pass compiler (mostly). The benefit is that it is fast. The price is that there are some things that are not possible.

Reference types can be forward declared because their size are always known (=SizeOf(pointer)). The size of record types are not known until they have been fully declared. This means that the compiler cannot determine the layout of a record type if it contains other record types that have not been fully declared, and it needs to know the layout in order to generate the code that uses it.

This problem can be solved, with certain limitations, while still staying a one-pass compiler, but at a cost of added complexity in the compiler and longer compile time.

Is this different than Classes with forward declarations?

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

×