Search code examples
delphiobjectlazarus

How do you pass objects between functions?


Suppose I have a function:

function someFunction: TStringList;  
begin  
  result:=TStringList.Create;  
  if someConditionIsTrue then  
    result:=doSomething;  
  //other code  
end; 

And the function doSomething:

function doSomething: TStringList;
begin
  result:=TStringList.Create;
  result.Add(something);
end;

If I run this code everything works as hoped, but I'm still wondering if this is the "proper" way to pass around an object like a stringlist?

The stringlists are never freed, and I wonder if passing around objects this way could get complicated or confusing when it came to debugging or someone else trying to understand the code.


Solution

  • The "proper" approach is for you to establish your own rules for how things get destroyed. It's fine to create objects in a function result, but only if you are following your own strict rules.

    In your case, SomeFunction has a memory leak. First, you create a TStringList, and then if some condition is met, you create another TStringList in its place, completely disregarding the first one. Thus, leaking memory.

    DoSomething shouldn't be a function returning a string list, if there's a possibility that you might already have one created. Instead, just make it a procedure...

    procedure DoSomething(AList: TStringList);
    begin
      AList.Add(Something);
    end;
    

    Once you do that, then SomeFunction should look like this:

    function someFunction: TStringList;  
    begin  
      Result:= TStringList.Create;  
      if someConditionIsTrue then  
        DoSomething(Result);  
      //other code  
    end; 
    

    "The stringlists are never freed"

    I hope this isn't by design. Everything you create must be free'd at some point, especially if you have functions that create their result. The only exception is if you create something that lives for the entire duration of the application, and even then it's extreme common-ground to free them anyway.


    On that note, the only time I ever create an object in a function result is when I'm encapsulating multiple lines of code which would otherwise be duplicated many times. For example, creating a query.

    Instead of repeating this code...

    Q:= TADOQuery.Create(nil);
    Q.Connection:= MyDatabaseConnection;
    Q.SetSomeOtherProperties;
    

    ...I put it in a function...

    function CreateQuery: TADOQuery;
    begin
      Result:= TADOQuery.Create(nil);
      Result.Connection:= MyDatabaseConnection;
      Result.SetSomeOtherProperties;
    end;
    

    Then, I can simply call this function whenever I need to repeat that code...

    Q:= CreateQuery;