Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2011-09

Converting records back and forth. (Forward declarations for records needed ?!?)

6 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Skybuck Flying

Hello,

I want to write code as follows and I will simplify it here to illustrate the problem.

Let's say I want to kinds of records: TrecordA and TrecordB.

I want to be able to convert types of TrecordA to TrecordB but I also want to be able to convert types of TrecordB to TrecordA.

So I was thinking of writing code as follows:

type
    TrecordA = record
        function ToRecordB : TrecordB;
    end;
    TrecordB = record
        function ToRecordA : TrecordA;
    end;

These two functions would return a value type/a copy of itself but converted.

However there is ofcourse a problem, there is a circular reference, and as far as I know delphi or free pascal cannot forward declare records ?

I could use forward pointers perhaps, but that would be a bit weird and might lead to bugs because of automatic stack variables/value types being automatically cleaned up, using pointers would pretty much dismiss the value types, I could also use dynamic memory but this would create further problems, since records do no have destructors, the last possible option is using classes instead of records, so then class forward declarations could be used, but the records are kinda simply and classes is probably a bit overkill.

So to me it seems this basic functionality that I seek seems to be missing from the object pascal/delphi language, so perhaps it can be added to a future version ?

Bye,
Skybuck.

Reply by email

Skybuck Flying

There appears to be a solution in Delphi for this:

It's called "record helpers":

Demonstration program:

// *** Begin of Test Program ***
program TestProgram;
{$APPTYPE CONSOLE}

{

Test circular records problem and solutions.

version 0.01 created on 19 september 2011 by Skybuck Flying

The solution below uses a "record helper" which seems to solve it nicely and now I can write the code the way I want to...

Not sure if it compiles in free pascal, but it does compile in Delphi XE at least ;)

(Perhaps another solution could be to use type casting, but that would not solve
the circular problem, so not going to test that)

}

uses
SysUtils;
type
TrecordB = record
private
  mData : double;
public
  property Data : double read mData write mData;
end;
TrecordA = record
private
  mData : integer;
public
  property Data : integer read mData write mData;
  function ToRecordB : TrecordB;
end;
// solution: record helper
TrecordBhelper = record helper for TrecordB
private
//  mData : double;
public
//  property Data : double read mData write mData; // must be in TrecordB
apperently ?!?
  function ToRecordA : TrecordA;
end;
function TrecordA.ToRecordB : TrecordB;
begin
result.mData := mData;
end;
function TrecordBhelper.ToRecordA : TrecordA;
begin
result.mData := Round(mData);
end;
procedure Main;
var
vRecordA : TrecordA;
vRecordB : TrecordB;
begin
writeln('program started');
vRecordA.mData := 555;
vRecordB.mData := 666.666;
writeln( 'vRecordA.mData: ', vRecordA.mData );
writeln( 'vRecordB.mData: ', vRecordB.mData );
writeln( 'vRecordA.ToRecordB.mData: ', vRecordA.ToRecordB.mData );
writeln( 'vRecordB.ToRecordA.mData: ', vRecordB.ToRecordA.mData );
writeln('program finished');
end;
begin
try
  Main;
except
  on E: Exception do
   Writeln(E.ClassName, ': ', E.Message);
end;
ReadLn;
end.
// *** End of Test Program ***

Bye,
Skybuck.

Reply by email

Skybuck Flying

Hmm, interesting, the problem returns when TrecordA and TrecordB are each put into their own units.

The problem turns from a "circular record" problem into a "circular unit" problem :(

I guess only way to solve it is to place both types into the same unit ?

Or perhaps there is another way, perhaps the new unit extension mechanism... hmm...

Bye,
Skybuck.

Reply by email

Sven Barth
to Skybuck Flying: There appears to be a solution in Delphi for this: It's called "record helpers":…
Skybuck Flying wrote
Not sure if it compiles in free pascal, but it does compile in Delphi XE at least ;)

See here: http://wiki.freepascal.org/Helper_types

Show quoted text 7 lines
// solution: record helper TrecordBhelper = record helper for TrecordB private // mData : double; public // property Data : double read mData write mData; // must be in TrecordB apperently ?!?

Helper types must not contain fields as they aren't instantiated.

Regards,
Sven

Reply by email

Hans-Peter Diettrich
to Skybuck Flying: I want to write code as follows and I will simplify it here to illustrate the problem.…
Show quoted text 20 lines
Hello, I want to write code as follows and I will simplify it here to illustrate the problem. Let's say I want to kinds of records: TrecordA and TrecordB. I want to be able to convert types of TrecordA to TrecordB but I also want to be able to convert types of TrecordB to TrecordA. So I was thinking of writing code as follows: type TrecordA = record function ToRecordB : TrecordB; end; TrecordB = record function ToRecordA : TrecordA; end;

That's the wrong way. You should pass in an parameter of the output type, allocated by the caller. Then pass it as a pointer, and declare the pointer types before the records.

DoDi

Reply by email

Flávio Etrusco
to Sven Barth: See here: http://wiki.freepascal.org/Helper_types Helper types must not contain fields as…

And this feature can be implemented with operators, but this is discussion for fpc-pascal, I guess.

-Flávio

Sven Barth wrote 23 lines
Am 19.09.2011 12:32, schrieb Skybuck Flying: > > Not sure if it compiles in free pascal, but it does compile in Delphi XE > at least ;) See here: http://wiki.freepascal.org/Helper_types > // solution: record helper > TrecordBhelper = record helper for TrecordB > private > // mData : double; > public > // property Data : double read mData write mData; // must be in TrecordB > apperently ?!? Helper types must not contain fields as they aren't instantiated. Regards, Sven _______________________________________________ fpc-devel maillist  -   http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email