How to properly Free class instances created as actual parameters to methods in Delphi

I am having some difficulty in understanding how to free up instances of objects created on the fly.
I am translating some java/c# code into Delphi.  The c# is itself a translation of the original java.  So, I have two source materials from which to compare my efforts.
I understand that both these languages feature garbage collectors to free the writer from having to explicitly manage his instance's life span.  So, there's no direct guide from which to see when their instances are freed.
The code is an implementation of the DoubleDouble type with methods that manipulate the type's value by arithmetic and functional means.  Several creators exist to allow creation of an instance of the DD value from a double, another DD or by parsing a string representation.  Arithmetic methods permit the chaining of operations together in a sort of pre/post/infix blend that resembles the mathematical expression that's being calculated.  These arithmetic, and some unshown mathematical function methods, call the class' creators as they need.
An example:
type
  TDD = class
    constructor Create( v : double );
    constructor Create( v : TDD );
    destructor Destroy;
    function Add( yhi : double; ylo : double ): TDD;
    function selfAdd( yhi : double; ylo : double ): TDD;
    function selfDivide( y : double ): TDD;
    function selfDivide( yhi : double; ylo : double ): TDD;
  end;
implementation
  function TDD.Add( y : double ): TDD;
  begin
    Result := TDD.Create( Self );
    Result.selfAdd( y );
  end;
  function TDD.selfAdd( y : TDD ): TDD;
  begin
    Result.selfAdd( y.hi, y.lo );
  end;
  function TDD.selfAdd( yhi : double; ylo : double ): TDD;
  begin
    < code to calculate DoubleDouble addition of self by yhi and ylo >
    Result := self;
  end;
  function TDD.selfDivide( y : double ): TDD;
  begin
    Result := selfDivide( v, 0.0 );
  end;
  function TDD.selfDivide( yhi : double; ylo : double ): TDD;
  begin
    < code to calculate DoubleDouble division of self by yhi and ylo >
    Result := self;
  end;
var
  c : TDD;
begin
  c := TDD.Create( 1 ).selfDivide( TDD.Create( 9 ).add( 3 ));
  writeln( c );
  c.Free;
end.

Open in new window

The issue is that this code leaks memory because implicit TDD instances are created within the expression and I can't figure out where and how to free them up.  Getting a hold of the reference of each to free them eludes me.
Sorry if this is common knowledge and I'm asking it again, but, nothing I google addresses this in a way that I can see to solve my problem.
scox12Asked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

SteveBayCommented:
I see a number of errors or typos in this code so those need to be resolved....

Some general guidelines as far as object creation and freeing:
If you create an object in a procedure try to free that object in the same procedure
begin
   c := TDD.create(3)
   // use c
   c.free;
end;

Open in new window


If you create an object in a constructor then free the object in the destructor.
constructor TDD.Create(v: TDD);
begin
     fDD := TDD.Create(v);
end;

destructor TDD.Destroy;
begin
     fDD.free;
end;

Open in new window


I also recommend you avoid calling member routines on the same line as you create and object. It leads to confusion and is unnecessarily clever.  So This:
c := TDD.Create( 1 ).selfDivide( TDD.Create( 9 ).add( 3 ))

Open in new window

Becomes something like this:
d := TDD.Create( 9 )
d.add(3); 
c := TDD.Create( 1 );
c.selfDivide(d);
...
c.free;
d.free;

Open in new window

Unfortunately there are fundamental errors in your code. For example the selfDivide takes a double as a parameter yet you are passing an object reference to a TDD in. So the code example I provided is erroneous regardless.
Sinisa VukSoftware architectCommented:
You should use TInterfacedObject....

Here is my simple example:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ActiveX;

type
  TDD = class(TInterfacedObject)
    lo, hi: Double;
    constructor Create( v : double ); overload;
    constructor Create( v : TDD ); overload;
    function Add( y : double ): TDD; overload;
    function Add( y : TDD ): TDD; overload;
    function Add( yhi : double; ylo : double ): TDD; overload;
    function Divide( y : TDD ): TDD; overload;
    function Divide( y : double ): TDD; overload;
    function Divide( yhi : double; ylo : double ): TDD; overload;
  end;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  c: TDD;
begin
  c := TDD.Create( 1 ).Divide( TDD.Create( 9 ).Add( 3 ));
  Button1.Caption := FloatToStr(c.lo);
end;

{ TDD }

constructor TDD.Create(v: double);
begin
  Self.lo := v;
  Self.hi := 0;
end;

constructor TDD.Create(v: TDD);
begin
  Self.lo := v.lo;
  Self.hi := v.hi;
end;

function TDD.Add( y : double ): TDD;
begin
  Result := Self.Add(0.0, y);
end;

function TDD.Add( y : TDD ): TDD;
begin
  Result := Self.Add( y.hi, y.lo );
end;

function TDD.Add(yhi, ylo: double): TDD;
begin
  //< code to calculate DoubleDouble addition of self by yhi and ylo >
  lo := lo+ylo;
  Result := self;
end;

function TDD.Divide(y: double): TDD;
begin
  Result := Self.Divide(0.0, y);
end;

function TDD.Divide(yhi, ylo: double): TDD;
begin
  //< code to calculate DoubleDouble division of self by yhi and ylo >
  lo := lo/ylo;
  Result := Self;
end;

function TDD.Divide(y: TDD): TDD;
begin
  Result := Self.Divide( y.hi, y.lo );
end;

end.

Open in new window


...another fine example....and here...

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
scox12Author Commented:
@SteveBay - Thanks for your observations.  I was sloppy in typing in the portions of the TDD class that I gave in the example.  The constructors, destructors and the arithmetic methods are properly implemented in the actual code and do manage to produce the correct arithmetic results.  
You're certainly correct, the arithmetic methods are themselves constructors and return instances of TDD.  This seems quite acceptable in the java/c# and my direct translation prevents me from freeing what's created in the same method.  I've read of and see the drawbacks of failing to abide by this.
The line of code that you've noted as leading to confusion and as being unnecessarily clever is indeed the one that is the base of the difficulties.  It is a direct pascalization of the java and c# from the code I'm translating.  In my defense, the cleverness does lead to the expression being rather readable as an arithmetic analog, wouldn't you say?   Because there is considerable code to translate and these sorts of arithmetic expressions permeate the java, I'd like to retain these expressions for as long as possible to ease my translation task.  That way, I won't be introducing my own misinterpretation errors.
@Sinisa Vuk - Thank you too for pointing out the virtues of inheriting from TInterfacedObject.  I'd implemented some other classes during this translation using TInterfacedObject and interfaces of one sort or another.  I'd not appreciated these memory management aspects of the class.  Thanks for including the links to their explanations.
I'll make the change to descend from TInterfacedObject and see what happens and report back.
Bye-the-bye, the code I'm working from is the JTS and NTS topology suites.  It looked to me that you'd seen where I was coming from in your responding example code.  Thanks, here goes...
Exploring ASP.NET Core: Fundamentals

Learn to build web apps and services, IoT apps, and mobile backends by covering the fundamentals of ASP.NET Core and  exploring the core foundations for app libraries.

Geert GOracle dbaCommented:
wow ... you're really mixing up some techniques

i see the use of fluid interfaces
> this means the return value of the methode function is self
in code: Result := Self;

misunderstanding of class (or object) and instance
a class is the blueprint of something
a instance is the physical embodiment of such a blueprint
sample:
  a house class: the architectural drawing
  a house instance: 1 of the actual houses built according to that architectural drawing

so this code is a wrong
function TDD.Add( y : double ): TDD;
  begin
    Result := TDD.Create( Self );

Open in new window


the variables you pass to the instance never get stored
you don't have any private variables defined in your class

basically you have an outline of the house on your architectural drawing
but all the plumbing, electrical, ... lines are missing

it would help if you provide the C# of Java class definitions

what are you trying to do ... using some math functions ?
check the Math unit ...
it holds a lot of functions to do such things

if the double type doesn't have enough precision the try and extended type
http://www.delphibasics.co.uk/Article.asp?Name=Numbers

type
  TDD = class(TInterfacedObject)
  private
    v: Extended;
  public
    constructor Create( v : Extended );
    function Add( y: Extended ): TDD;
    function Divide( y : Extended ): TDD;
    property Value: Extended read GetValue write SetValue;
  end;

implementation

function TDD.Add( y: extended  ): TDD;
begin
  Result := Self;
  v := v + y ;
end;

function TDD.Divide( y : Extended ): TDD;
begin
  Result := self;
  v := v / y;
end;

function TDD.GetValue: Extended;
begin
  Result := v;
end;

procedure TDD.SetValue(const y: Extended);
begin
  v := y;
end;

var
  c : TDD;
begin
  c := TDD.Create( 1 ).Divide( 9 ).add( 3 );
  writeln( c.Value );
end.

Open in new window


with interfaces you don't need to free
scox12Author Commented:
@Geert Gruwez - Thanks for your observations.  The purpose of the TDD class is to obtain greater precision without necessarily increasing the range of acceptable values.  The class calculates with 31 decimal digits of precision within the range of the double type.  The Delphi is a translation of the DD.java code available within the JTS Topology Suite at http://sourceforge.net/projects/jts-topo-suite.  Another source for comparison is the DD.cs source of NetTopologySuite within https://github.com/NetTopologySuite/NetTopologySuite.  
The result of the actual small program and support units that I (poorly) gave as an example is: "0.083333333333333333333333333333332".
scox12Author Commented:
Thanks Sinisa Vuk for your suggestion to base the TDD class on interfaces.  
I defined an interface descendant and placed the method definitions for its Divide, SelfDivide, negate, sqrt, sqr and etc., in it.  I then used that interface type on my TDD = class( TinterfacedObject, IDD ) statement and in the TDD method's definitions.  I changed all the formal parameter and function result types from TDD to IDD.  Once I fixed all my typos, it compiled and still passes the DUnit tests that I'd written to test every arithmetic and function method.  Additionally, FastMM4 with FullDebugMode, EnableMemoryLeakReporting, LogMemoryLeakDetailToFile and Log ErrorsToFile not longer reports even a single memory leak.  The former code generated some 43 leaks.
Pascal Analyzer complains about a few minor things but not over things related to what I've done to implement your suggestions.  
On the whole, I've learned that interfaces can be used productively and that I can continue my translation effort without leaving a big unsolved issue hanging in the wind.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.