Jump to content
pcoder

alternative to call parameter?

Recommended Posts

procedure TObj.run;
var r: TRecord;
begin
...; processRecord( r); ...;
end;

ProcessRecord is a method and contains many nested calls (more methods).
The issue is that many methods would need an additional parameter (very cumbersome).
Therefore an alternative is wanted. Object-field FR (PRecord) is a pointer (rather than record) to reduce memory outside of runs.

is there any preference for one of them?

procedure TObj.run2;
begin
  new( FR); 
  ...; processRecord; ...;
  dispose(FR);
  FR := nil;
end;
procedure TObj.run3;
var r: TRecord;
begin
  FR := @r; 
  ...; processRecord; ...; 
  FR := nil;
end;

 

Share this post


Link to post
Posted (edited)

I would choose the latter. No need to allocate memory dynamically unless the record instance needs to live after TObj.run3() exits. 

 

But, if you have a lot of methods of TObj that are acting on the record then they should instead be methods of TRecord itself. Consider refactoring your code to make it cleaner.

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post

May I suggest "fluent interfaces" as an alternative to nested calls.

 

Instead of using a record like a dumb data store that is only manipulated from the outside, you can put the methods that fiddle with the record's contents directly into the record itself and thus keep the code and the data closely together.  Also, this enables one to use a so-called "fluent interface".

 

Example:

 

This is an example of a record that contains just one integer member, "data".  In real life, you can make the record as complex as you want.

type
  pMyrecord=^tMyRecord;

  tMyRecord=Record
     data:integer;
     Function Reset:pMyrecord;
     Function Add (x:integer):pMyrecord;
     Function Multiply (x:integer):pMyrecord;
     Function Divide (x:integer):pMyrecord;
  End;

 

As you can see, all the methods in this record return a pointer, which simply points to the record itself. That is the "secret sauce" one needs to implement fluent interfaces.

 

function tMyRecord.Add(x: integer): pMyrecord;
begin
  data:=data+x;
  result:=@self;
end;

function tMyRecord.Divide(x: integer): pMyrecord;
begin
  data:=data div x;
  result:=@self;
end;

function tMyRecord.Multiply(x: integer): pMyrecord;
begin
  data:=data*x;
  result:=@self;
end;

function tMyRecord.Reset: pMyrecord;
begin
   data:=0;
   result:=@self;
end;

 

Now the cool thing: All these methods can be concatenated and will be processed left-to-right. This produces very legible and compact code:

 

procedure Test;
var x:tmyrecord;
begin
    x.reset.add(12).multiply(4).divide(2);
end;

 

 

(edit)

Note that I didn't do a single heap allocation here, never manually passed the record as a parameter and never did a nested call.  The data lives on the stack.

 

If the record contains managed objects such as strings, these are disposed of automatically.

Edited by A.M. Hoornweg
  • Like 2

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

×