Michel Hua
Michel Hua

Reputation: 1777

Delphi Reference Parameter / Default parameter

Let's say I have an object which I would like to copy.

interface

type
  TPerson = Class(TObject)
  public
    first_name: string;
    last_name: string;
    address: string;
  public
    constructor Create;
    procedure CopyTo(var s1, s2, s3: string);
  ...

implementation

...

procedure TPerson.CopyTo(var s1, s2, s3: string)
begin
  s1 := first_name;
  s2 := last_name;
  s3 := address;
end;

end.

Then I can use my class like this :

...
var
  name1, name2, address: string;
begin
  person := TPerson.Create;
  person.first_name = 'John';
  person.last_name = 'Doe';
  person.address = '10 Downing Street';
  person.CopyTo(name1, name2, address);
end;

But if I am not interested in copying the address, I would like to be able to use it like this

...
var
  name1, name2: string;
begin
  person := TPerson.Create;
  person.first_name = 'John';
  person.last_name = 'Doe';
  person.address = '10 Downing Street';
  person.CopyTo(name1, name2);

  // Some bad legacy code that has a lot more unstructured fields
end;

I was thinking of writing an overload CopyTo(var s1, s2: string) or using as many buffer variables as number of string I want to forget ?

Is there a more elegant way ?

Thanks.

Upvotes: 0

Views: 358

Answers (3)

NGLN
NGLN

Reputation: 43659

Let's say I have an object which I would like to copy.

Strictly speaking, that is not what you are doing here. Sure, things are being copied, but to variables, not to an object. And considering that the reference parameters, due to making use of variabels, are bothering you from specifying default values, I suggest to do your copying to an actual copy of the whole object.

Design the TPerson class of type TPersistent that has kind of a build-in copy mechanism (to be implemented/expanded by the designer) and extend the constructor with default parameters:

type
  TPerson = Class(TPersistent)
  private
    FFirstName: String;
    FLastName: String;
    FAddress: String;
  public
    procedure Assign(Source: TPersistent); override;
    constructor Create(AFirstName: String = ''; ALastName: String = '';
      AAddress: String = ''); overload;
    constructor Create(APerson: TPerson); overload;
    property FirstName: String read FFirstName write FFirstName;
    property LastName: String read FLastName write FLastName;
    property Address: String read FAddress write FAddress;
  end;

procedure TPerson.Assign(Source: TPersistent);
begin
  if Source is TPerson then
  begin
    FFirstName := TPerson(Source).FFirstName;
    FLastName := TPerson(Source).FLastName;
    FAddress := TPerson(Source).FAddress;
  end
  else
    inherited Assign(Source);
end;

constructor TPerson.Create(AFirstName, ALastName, AAddress: String);
begin
  inherited Create;
  FFirstName := AFirstName;
  FLastName := ALastName;
  FAddress := AAddress;
end;

constructor TPerson.Create(APerson: TPerson);
begin
  inherited Create;
  Assign(APerson);
end;

And now, your possibillities vary from:

procedure Example1;
var
  Person: TPerson;
  PersonCopy: TPerson;
begin
  Person := TPerson.Create;
  Person.FirstName := 'John';
  Person.LastName := 'Doe';
  Person.Address := '10 Downing Street';
  PersonCopy := TPerson.Create;
  PersonCopy.Assign(Person);
  //...
end;

to:

procedure Example2;
var
  Person: TPerson;
  PersonCopy: TPerson;
begin
  Person := TPerson.Create('John', 'Doe');
  PersonCopy := TPerson.Create(Person);
  //...
end;

Upvotes: 0

Rob Kennedy
Rob Kennedy

Reputation: 163287

Your question title suggests you want some kind of default parameter for the parameters you're not interested in using. Delphi doesn't support that feature. (Neither does any other language I'm aware of.) You would have to write separate functions for each combination of fields you wanted to get copies of. They can be overloads of a single name, or they can all have names indicating which fields they return; you might need separate names if the types alone don't differentiate all the combinations you wish to support.

But before you do that, take a step back and consider your goal. You've written a function that copies values from public members into variables. Why does that function need to exist at all? Just copy the members you need:

person.first_name = 'John';
person.last_name = 'Doe';
person.address = '10 Downing Street';
name1 := person.first_name;
name2 := person.last_name;

Another approach is to write a proper constructor for your class so you don't have to initialize all its fields after it's already been created. Keep copies of the values you want in advance:

name1 := 'John';
name2 := 'Doe';
person := TPerson.Create(name1, name2, '10 Downing Street');

Upvotes: 2

Iridio
Iridio

Reputation: 9271

In my opinion using the overloads with some more descriptive variables is the best approach. I always try to make intention revealing interfaces and names

Upvotes: 0

Related Questions