Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting object as a result from func/proc in Delphi

What is the best practice for returning simple objects from functions / procedures in delphi?

eg. 2 kinds of code:

pass created object as reference, populate object in Proc, destroy it afterwards

procedure Proc(var Obj: TMyObject);
begin
  // populate Obj
end;

O := TMyObject.Create;
try
  Proc(O);
  // manipulate populated object
finally
  O.Free;
end;

or get created object as result from function, destroy after manipulation

function Func: TMyObj;
begin
  Result := TMyObj.Create;
end;

O := Func;
if O <> nil then
begin
  try
    // manipulate
  finally
    O.Free;
  end;
end;
like image 336
Juraj Blahunka Avatar asked Nov 08 '09 17:11

Juraj Blahunka


1 Answers

There is no best practice. The primary thing you should do, though, is to make sure it's always clear who is responsible for destroying the object at any given time, even when an exception occurs.

There's nothing wrong with a function creating a new instance and returning it. Such a function is a factory. You can treat it just like a class's constructor, so you should make sure that it behaves like a constructor: Either return a valid object or throw an exception. It never returns a null reference.

function Func: TMyObj;
begin
  Result := TMyObj.Create;
  try
    Result.X := Y;
  except
    Result.Free;
    raise;
  end;
end;

That's an exception-handling pattern you don't see very often, but it's important for this style of function. Returning the object transfers ownership from the function to the caller, but only if it manages to execute completely. If it has to leave early because of an exception, it frees the object because the caller has no way to free it itself. (Functions that terminate due to an exception do not have return values.) The caller will use it like this:

O := Func;
try
  writeln(O.X);
finally
  O.Free;
end;

If there's an exception in Func then O never gets assigned, so there's nothing available for the caller to free.


When the caller creates the object and you pass it to another function to initialize it, do not make the parameter a "var" parameter. That places certain restrictions on the caller, who must use a variable of exactly the type requested by the function, even if some descendant type was created instead.

Such a function should not free the object. The caller doesn't grant ownership responsibility to the functions it calls, especially when it plans on using the object after the function returns.

like image 94
Rob Kennedy Avatar answered Sep 18 '22 04:09

Rob Kennedy