Solve quadratic equation

If you want to see a preview in the play store go here.

This code is helpful to solve quadratic equations with delphi!

unit TEqSecDeg;


System.SysUtils, System.Math, System.Generics.Collections;

TInequalitySolKind = (extsol, intsol, always, never, almostalways);

TQuadraticErr = class(Exception)
constructor Create(const errMsg: string);

//main class that solves second degree equations
TEqSecDegree = class
a, b, c: double;
delta: double;
solRealCount: integer;
solImaginaryCount: integer;
class var currentIstances: integer;
class var totalIstances: integer;
function getDelta(const vala, valb, valc: double): double; overload;
constructor Create(const a, b, c: double); overload;
constructor Create(const a, b, c: string); overload;
destructor Destroy; override;
function getDecimal(const s: string): double; //fraction to decimal
function getDelta: double; overload;
function getSolutions(aList: TList): boolean; virtual;
class function toFraction(value: double): string;
property valueOfA: double read a;
property valueOfB: double read b;
property valueOfC: double read c;
property realSolutionsCount: integer read solRealCount;
property imaginarySolutionsCount: integer read solImaginaryCount;
class property currentEquationsCount: integer read currentIstances;
class property totalEquationsCount: integer read totalIstances;


class function TEqSecDegree.toFraction(value: double): string;
var h1, h2, k1, k2, y, a, aux: double;
sign: string;

//Setup the values
h1 := 1;
h2 := 0;
k1 := 0;
k2 := 1;
y := abs(value);

//Generates the fraction
a := floor(y);
aux := h1;
h1 := a * h1 + h2;
h2 := aux;
aux := k1;
k1 := a * k1 + k2;
k2 := aux;
if (y – a = 0) or (k1 = 0) then break;
y := 1 / (y – a) ;
until (Abs(abs(value) – h1 / k1) <= abs(value) * 0.000001); //Check if returning a - in front of the fraction if 'x' was < 0 if (value < 0) then begin sign := '-'; end else begin sign := ''; end; //Output if not(h1 = 0) then begin Result := sign + FloatToStr(h1) + '/' + FloatToStr(k1); end else begin Result := sign + '0'; end; end; { TEqSecGrado } constructor TEqSecDegree.Create(const a, b, c: double); begin //inherit from TObject inherited Create; //Set up the initial parameters Self.a := a; Self.b := b; Self.c := c; delta := 0; solRealCount := 0; solImaginaryCount := 0; Inc(currentIstances); Inc(totalIstances); end; constructor TEqSecDegree.Create(const a, b, c: string); begin //inherit from TObject inherited Create; //Set up the initial parameters Self.a := getDecimal(a); Self.b := getDecimal(b); Self.c := getDecimal(c); delta := 0; solRealCount := 0; solImaginaryCount := 0; Inc(currentIstances); Inc(totalIstances); end; destructor TEqSecDegree.Destroy; begin //Reset everything delta := 0; solRealCount := 0; solImaginaryCount := 0; Dec(currentIstances); //Destroy inheriting from TObject the method inherited; end; function TEqSecDegree.getDecimal(const s: string): double; var BarPos: integer; numStr, denomStr: string; x: double; begin BarPos := Pos('/', S); if (TryStrToFloat(s, x)) then begin Result := x; exit(); end; if BarPos = 0 then raise TQuadraticErr.Create('Fraction separator symbol "/" not found.'); numStr := Trim(Copy(S, 1, BarPos - 1)); denomStr := Trim(Copy(S, BarPos + 1, Length(S))); Result := StrToFloat(numStr)/StrToFloat(denomStr); end; function TEqSecDegree.getDelta: double; begin Result := delta; end; function TEqSecDegree.getDelta(const vala, valb, valc: double): double; begin Result := (valb*valb) - 4*vala*valc; end; function TEqSecDegree.getSolutions(aList: TList): boolean;
var tempDelta: double;


delta := getDelta(a,b,c);

if (a <> 0) then

if (delta >= 0) then

aList.Add((-b + sqrt(delta))/(2*a));
aList.Add((-b – sqrt(delta))/(2*a));

//set solutions count
if (aList[0] <> aList[1]) then
solRealCount := 2;
solRealCount := 1;

solImaginaryCount := 0;
Result := true;


tempDelta := abs(delta);

//set solutions count
if (aList[1] <> aList[3]) then
solImaginaryCount := 2;
solImaginaryCount := 1;

solRealCount := 0;
Result := true;



//Raise exception when this is not a second degree equation
raise TQuadraticErr.Create(‘The first parameter “a” cannot be zero.’);


Result := false;


{ TQuadraticErr }

constructor TQuadraticErr.Create(const errMsg: string);
inherited Create(errMsg);


The congruence class

This is my component for congruences. Enjoy!

unit uCongruences;


System.Classes, System.Math, System.SysUtils;

TCongrSolutions = array of integer;

TCongrError = class(Exception)

TCongruence = class(TComponent)
a, b, n, numClass: integer;
solutions, vals: TCongrSolutions;
hasSolutions: boolean;
function divides(a, b: integer): boolean;
function gcd(a,b: integer): integer;
function gcdExtended(p, q: integer): TCongrSolutions;
function modulo(a, b: integer): integer;
procedure sort(a: TCongrSolutions);
constructor Create(AOwner: TComponent; a, b, n: integer); reintroduce;
function getSolution: TCongrSolutions; virtual;
class function solveSystem(const a: array of TCongruence; setClass: boolean): integer;
class function modinv(u, v: integer): integer;
class function getGCD(u, v: integer): integer;
property getClass: integer read numClass;
property hasSol: boolean read hasSolutions;
property valA: integer read a write a;
property valB: integer read b write b;
property valN: integer read n write n;

procedure Register;


procedure Register;
RegisterComponents(‘AlbertoComp.’, [TCongruence]);

{ TCongruence }

constructor TCongruence.Create(AOwner: TComponent; a, b, n: integer);

inherited Create(AOwner);
Self.a := a;
Self.b := b;
Self.n := n;
numClass := 0;
hasSolutions := false;

SetLength(solutions, 0);


function TCongruence.divides(a, b: integer): boolean;
Result := not(modulo(a, b) > 0);

function TCongruence.gcd(a, b: integer): integer;
var remd: integer;

remd := a mod b;

if remd = 0 then
Result := b
Result := gcd(b, remd);


function TCongruence.gcdExtended(p, q: integer): TCongrSolutions;

SetLength(Result, 3);

if (q = 0) then
Result[0] := p;
Result[1] := 1;
Result[2] := 0;
vals := gcdExtended(q, modulo(p,q));
Result[0] := vals[0];
Result[1] := vals[2];
Result[2] := vals[1] – vals[2]*floor(p/q);


class function TCongruence.modinv(u, v: integer): integer;
var u1, u3, v1, v3, t1, t3, q, iter: integer;

u1 := 1;
u3 := abs(u);
v1 := 0;
v3 := v;
iter := 1;

while (v3 <> 0) do
q := u3 div v3;
t3 := u3 mod v3;
t1 := u1 + q*v1;
u1 := v1; v1 := t1; u3 := v3; v3 := t3;
iter := -iter;

if (u3 <> 1) then
raise TCongrError.Create(‘The result is zero.’);
Result := 0; //errore

if (iter < 0) then Result := v-u1 else Result := u1; end; function TCongruence.modulo(a, b: integer): integer; begin Result := ((a mod b) + b) mod b; end; class function TCongruence.solveSystem(const a: array of TCongruence; setClass: boolean): integer; var i, n, t: integer; begin Result := 0; n := 1; for i := Low(a) to High(a) do begin if (a[i].a <> 1) then
raise TCongrError.Create(‘The value of ”a” must be 1. With a = ‘
+ a[i].a.toString + ‘ it is not possible to apply the chinese remainder theorem.’);

if not(a[i].n > 0) then
raise TCongrError.Create(‘The condition n > 0 is not verified. [ n = ‘ + a[i].n.toString +’ ]’);

n := n * a[i].n;

for i := Low(a) to High(a) do
t := (n div a[i].n);
Result := Result + (a[i].b * t * modinv(t, a[i].n));

if ((Result > n) and setClass) then

Result := Result – n;
until (n > Result);


if ((Result < 0) and setClass) then begin repeat Result := Result + n; until ((n > Result) and (Result <> 0));



procedure TCongruence.sort(a: TCongrSolutions);
i, j, item: Integer;

//insertion sort
for i := Low(a)+1 to High(A) do begin
item := a[i];
j := i-1;

while (j >= Low(a)) and (a[j] > item) do
a[j+1]:= a[j];

a[j+1] := item;


class function TCongruence.getGCD(u, v: integer): integer;
var remd: integer;

remd := u mod v;

if remd = 0 then
Result := v
Result := getGCD(v, remd);


function TCongruence.getSolution: TCongrSolutions;
var m, i: integer;
tmp: TCongrSolutions;

//gcd(a,n) non divide b
if ((b mod gcd(a,n)) <> 0) then
hasSolutions := false;
raise TCongrError.Create(‘b doesn”t divide gcd(a,n)’);

m := abs(n);
a := modulo(a,m);
b := modulo(b,m);
tmp := gcdExtended(a, m);

if not(divides(b, tmp[0])) then
SetLength(solutions, 0);
hasSolutions := false;
Result := solutions;
SetLength(solutions, tmp[0]);
solutions[0] := modulo( (tmp[1] * (b div tmp[0])) , m);

for i := 1 to tmp[0]-1 do
solutions[i] := modulo( (solutions[0] + i*(m div tmp[0])) , m);

numClass := n div tmp[0];
hasSolutions := true;
Result := solutions;



Summary of the technologies

The IoT is a brand new world to explore for mobile developers. There is still
no clear market leader, and different companies do the IoT their own way.

  • One aspect of IoT that everybody agrees on is the fact that it is all about
    communicating with things, sometimes very far from a traditional computer
    or a mobile device. Those devices, gadgets, and sensors sometimes
    communicate using a traditional internet TCP/IP protocol, but in most cases
    they use protocols optimized for low energy consumption and IoT use cases.
    One of the key communication protocols that enables IoT today is Bluetooth
    Low Energy.
  • Delphi comes with very good support for building both mobile and desktop
    apps that are using Bluetooth LE. You can build Bluetooth LE clients, but it
    is also possible to implement GATT servers that emulate Bluetooth LE
  • We have learned about interacting with the Internet of Things.
    We have started from using plain Bluetooth LE protocol with the
    TBluetoothLE component and then moved to specialized support for standard
    Bluetooth devices, such as heart monitors and beacons for building proximity
    apps. We have also looked into BeaconFence technology for building
    complete GPS-free positioning solutions and the app tethering framework for
    having two arbitrary Delphi apps exchange data over Bluetooth or TCP/IP
    with almost no coding required.

    The data access logic has been implemented and it is available through the
    IToDoData interface. This should be the only way for the user interface logic
    to access the data. That is why we are going to implement the GetToDoData
    method in the main form’s unit that will return the reference to the data access

    Expand the ItemAppearance node under lstvwToDos in the Structure View
    and click on the item node. Here we can see the elements that will make up a
    single row in the list view. There are also separate nodes for setting header,
    footer, and, additionally, the layout of the item in the edit mode. By default,
    the Appearance property of a list view item is ListItem and the height of a
    single row is 44. The default ListItem appearance will display just a line of
    text and the greater than sign at the right side of the item as an Accessory. By
    selecting different elements of the list view in the structure view, we can
    easily adjust their properties in the object inspector.

    In our app, a single To-Do item consists of Title and Category. Change the
    Appearance property of a list view item to ListItemRightDetail. Notice
    that changing the Appearance property changes the number of items under
    the item node.

Delphi customized styles for us

If we do not want to use a built-in style, we can always use a custom style.
The Delphi installation comes with a number of custom styles. In Delphi 10.2
on Windows 10, FireMonkey custom styles are installed into the
C:\Users\Public\Documents\Embarcadero\Studio\19.0\Styles directory.
FireMonkey styles are files with the *.style extension. If we preview a
FireMonkey style file with a text viewer, we will see that its content looks
very much like a form file that we design with Form Designer inside the

It is good practice not to put non-visual components such as stylebooks
directly on the form, but on a dedicated data module instead. Select File |
New | Other from the main menu. In the New Items dialogs, select the Delphi
Files category and choose to add a new Data Module to the project:

This is how our form will look like after loading the Transparent style on
iOS and on Android. I really like it. It has a nice gradient and the controls
look a little like those on a space ship dashboard from science-fiction movies.
It is a good practice to put stylebook components on a dedicated data module.
In this way we could have multiple forms reusing the same styles.

Another option to load a custom style is to use the TStyleManager class
defined in the FMX.Styles unit. It has different public class methods for
loading styles from a file or from a resource. The advantage of this approach
is the fact that a style is loaded globally for the whole.

Transparent style added to the project as a resource
Click on OK to close the Resources dialog. The next step is to write code that
will read the custom style from the resource and set it as a style for the whole
application. Because this is global to all forms, a logical place to enter this
code is in the project file itself. Click on the View Source… in the Project
menu. Add to the project’s uses clause FMX.Styles and a call to the
TStyleManager class to try to load a custom style from the resource:

uFormStylesTest in 'uFormStylesTest.pas' {FormStylesTest},
uFormExtra in 'uFormExtra.pas' {FormExtra};
{$R *.res}
Application.CreateForm(TFormStylesTest, FormStylesTest);
Application.CreateForm(TFormExtra, FormExtra);

If we select the Edit Default Style… option we will be modifying the
default style used by all controls of a given type. The option to Edit Custom
Style… will only change the style for a given control, without changing the
style for all other controls.
Right-click on the ArcDial1 control and select Edit Custom Style… from
the context menu. This will open the FireMonkey Style Designer and in the
Structure View we can see the individual components that a
TArcDial control is made of. It feels very much like editing a form, but we
are editing a style here. The Object Inspector can be used to modify
properties of all sub-elements of a style and we can also modify them visually
in the designer.

Let’s change something to see the effect in the running app. Let’s change the
size and color of the indicator ellipse. Change its Width property to 30 and its
Height to 10. Now it is bigger. Expand its Brush property and change the
Color property to Cornflowerblue. Refer to the following screenshot:

Delphi combinatorics app

I have created a component that is useful in math for Combinatorics! If you don’t know about them you can loot at here for more information about; below you can see a video of the component in action! I made this:

This is the relevant code:

 System.Math, System.SysUtils, Combinatorio, System.Classes;


 TCombinazioni = class(TInterfacedObject, ICombinatorio)
   n, k: integer;
   ripetizione: boolean;
   function fattoriale(const x: integer): integer;
   constructor Create(const n, k: integer; const ripetizione: boolean);
   function getSoluzioni(): integer;
   function getFormula(): string;

 TDisposizioni = class(TInterfacedObject, ICombinatorio)
   n, k: integer;
   ripetizione: boolean;
   function fattoriale(const x: integer): integer;
   constructor Create(const n, k: integer; const ripetizione: boolean);
   function getSoluzioni(): integer;
   function getFormula(): string;

 TPermutazioni = class(TInterfacedObject, ICombinatorio)
   n: integer;
   k: string;
   ripetizione: boolean;
   function fattoriale(const x: integer): integer;
   constructor Create(const n: integer; const k: string; ripetizione: boolean);
   function getSoluzioni(): integer;
   function getFormula(): string;

They implement interfaces so they are reference counted and you don’t need to call the Free! Very cool isn’t it? The main interface in particular is the following:

unit Combinatorio;


 ICombinatorio = interface
  function getSoluzioni(): integer;
  function getFormula(): string;



If you want to have the entire source code or the component, just leave a comment in the video! Happy coding!

Delphi main info that are a must know

In order to solve a problem using a computer, you need to define a finite set
of actions that operate on certain data or, in other words, to define an
algorithm. An algorithm expressed in a programming language is a computer
program, and its actions are described as programming language instructions.

One or more actions performed on certain data can be encapsulated in the
Object Pascal language as a routine or a class. In Object Pascal, routines are
called functions. If a function does not return a value, it is called a
procedure. Classes are the corner stones of object-oriented programming,
which is the most important approach to building apps in Object Pascal.
Objects group the data and the operations performed on this data together,
providing encapsulation and reusability.

The simplest possible type of program that can be written in Delphi is a
console application. It does not contain any graphical user interface. Console
programs can be executed from the command prompt and can optionally take
command-line parameters. A console application may output some text back
to the command line, perform some calculations, process files, or
communicate with remote services running somewhere on the internet. Let’s create a simple Delphi console app. It will be an interactive program
that will take our name from the command line and will display a greeting. In
the File menu, select New and Other. In the New Items window, make sure
that the Delphi Projects node is selected, and double-click on the Console
Application icon:

Always save a new project into an empty folder. Enter Greeter as the name
of the new project and click on OK. Notice that the IDE has changed the
identifier in the first line of the code and, also, the name of the file where the
program is stored. Every Delphi executable program source code needs to
start from the Object Pascal keyword, program, followed by the name of the

Delphi IoT and BLE

One of the most important communication protocols for IoT is Bluetooth. In
fact, there are two different Bluetooth technologies. The classic Bluetooth
and the newer, BLE, sometimes called smart Bluetooth; Bluetooth LE, or just
BLE for short. The classic Bluetooth is useful for data streaming and
provides data transfer rates up to 2 Mbps. It is commonly used in cars,
especially in hands-free headsets. It has much higher data transfer rates as
compared to BLE, but also much higher energy consumption.

The Bluetooth LE GATT profile describes a number of services. Each service
is a collection of characteristics. Each characteristic includes different
attributes. A GATT profile defines if a certain characteristic is mandatory or
optional. For example, in the Heart Rate Service, the Heart Rate
Measurement characteristic is mandatory, while Body Sensor Location and
Heart Rate Control Point are optional. Each characteristic is basically data
that you can write, read, or subscribe to in a BLE device of a certain kind. In
BLE, one party participating in communications acts as a GATT server and
another as a GATT client. The server exposes a set of attributes to a client
that are accessible using the attribute protocol. An attribute is the actual data.
It could be anything. It could be a heart rate value measured in beats per
minute, the state of a light switch, temperature, or something else.
Not every version of mobile operating systems and not every mobile device
type supports BLE and the specification itself is evolving too. That is why it
is important to pay attention if your combination of software and hardware
supports what you want to build.


The key types and classes for working with Bluetooth in Delphi are defined
in the System.Bluetooth unit. With Delphi, it is not only possible to build
GATT clients, but also to implement GATT servers. Similar to other
frameworks in Delphi, there are two levels of Bluetooth support. You can do
things in code, with types defined in System.Bluetooth, or you can use
reusable components, TBluetooth and TBluetoothLE, defined in the
System.Bluetooth.Components unit, that can make your life easier and act
as a wrapper to non-visual classes. In this chapter, we are going to focus
primarily on BLE, because this is the key protocol for IoT.

In the OnChange event of the checkbox, add the following line of code that
will enable the BLE component and start the discovery for available heart
rate monitors:

A_TIMEOUT = 3000;
 procedure TFormHRM.chkbxHRMChange(Sender: TObject);
 BluetoothLE1.Enabled := chkbxHRM.IsChecked;
  if BluetoothLE1.Enabled then
  BluetoothLE1.DiscoverDevices(A_TIMEOUT, [HRM_SERVICE]);

The first parameter to the StartDiscovery call is the timeout in milliseconds.
If we skipped the second parameter, we would find all BLE devices visible to
our app. That could be useful, if we would like to build a generic BLE
scanner, but in most cases we are just interested in connecting to a particular
device and getting from it a particular data.

Delphi check OS version

Building apps for multiple operating systems from the very same source code
imposes unique challenges. Your code might be running on iOS or Android.
It only takes two mouse clicks to recompile your app for a different target.
Certain features might exist on a given platform and not be there on other
platforms. Going further, new functionality is constantly being added to
platforms, so we may want to know on which platform and operating
system version your app is being executed.

This can be done with the TOSVersion record type defined in the
System.SysUtils unit. It has a class constructor that instantiates all its fields.
The TOSVersion record type has inner TArchitecture and TPlatform
enumerated types and corresponding public class properties to read the
current operating system architecture, platform, name, and major and minor
numbers. Additionally, we can check major and minor numbers of the service
pack level.

Here’s some code:


TOSArchitectureHelper = record helper for TOSVersion.TArchitecture
 function ToString: string;

TOSPlatformHelper = record helper for TOSVersion.TPlatform
 function ToString: string;

function OSArchToStr(const Value: TOSVersion.TArchitecture): string;
function OSPlatToStr(const Value: TOSVersion.TPlatform): string;


function OSArchToStr(const Value: TOSVersion.TArchitecture): string;
 case Value of
  arIntelX86: Result := 'IntelX86';
  arIntelX64: Result := 'IntelX64';
  arARM32: Result := 'ARM32';
  arARM64: Result := 'ARM64';
  else Result := 'Unknown OS Architecture';

function TOSArchitectureHelper.ToString: string;
 Result := OSArchToStr(self);

function OSPlatToStr(const Value: TOSVersion.TPlatform): string;
 case Value of
  pfWindows: Result := 'Windows';
  pfMacOS: Result := 'MacOS';
  pfiOS: Result := 'iOS';
  pfAndroid: Result := 'Android';
  pfWinRT: Result := 'WinRT';
  pfLinux: Result := 'Linux';
  else Result := 'Unknown OS Platform'

function TOSPlatformHelper.ToString: string;
 Result := OSPlatToStr(self);

Add this unit to the uses clause of the main form. We can additionally define
in the form class a simple Log(s: string) method that will just display a
given string in the memo.

Delphi TFraction class

I have created a component that allows you to easily manage fractions in Delphi! here you can see its implementation:

 TFraction = class(TComponent)
  strict private
   aNumerator: integer;
   aDenominator: integer;
   FOnReduced: TFracEvent;
   function GCD(a, b: integer): integer;
   constructor Create(AOwner: TComponent; aNumerator: integer; aDenominator: integer); reintroduce;
   function toString: string; reintroduce;
   function toDouble: double;
   procedure Reduce;
   class function Add(fraction1, fraction2: TFraction): TFraction;
   class function Subtract(fraction1, fraction2: TFraction): TFraction;
   class function Multiply(fraction1, fraction2: TFraction): TFraction;
   class function Divide(fraction1, fraction2: TFraction): TFraction;
   class function Negative(const Value: TFraction): TFraction;
   class function GetFraction(value: double): TFraction;
   property Numerator: integer read aNumerator write aNumerator;
   property Denominator: integer read aDenominator write aDenominator;
   property OnReduce: TFracEvent read FOnReduced write FOnReduced;

Basically that is a component that has the ability to create an in-memory representation of a fraction. Then you can make conversions (double to fraction or vice-versa) or operations among them. Here you can see a video in which I show you how to use it, it’s very easy!

Here there is the component registration part. Ask in a video comment for the complete source code! I have created two separated files (design time and runtime) so that you can add whatever you want to my component. Have fun!

unit uFractionRegister;



procedure Register;


procedure Register;
 RegisterComponents('AlbertoComp.', [TFraction]);


Delphi – Memory management tips

Memory management in Object Pascal is subject to two simple rules: You must destroy every object and memory block you create and allocate, and you must
destroy each object and free each block only once. Object Pascal supports three
types of memory management for dynamic elements, here we can see a list with a quick description:

  1. Every time you create an object, you should also free it. If you fail to do so, the
    memory used by that object won’t be released for other objects, until the program
  2. When you create a component, you can specify an owner component, passing the
    owner to the component constructor. The owner component (often a form or
    data module) becomes responsible for destroying all the objects it owns. In other
    words, when you free the form, it frees all the components it owns. So, if you create
    a component and give it an owner, you don’t have to worry about destroying
  3. When you allocate memory for strings, dynamic arrays, and objects referenced
    by interface variables (as discussed Chapter 11), Object Pascal automatically frees
    the memory when the reference goes out of scope. You don’t need to free a
    string: when it becomes unreachable, its memory is released. Something similar
    happens under ARC, as we’ll see later on.


In the most simple scenario, on desktop compilers you have to create the temporary
objects you destroy. Any non-temporary object should have an owner, be part of a
collection, or be reachable thought some data structure, which will become responsible
for destroying it in due time.


Another problem is that if you call the destructor of an object twice, you get an
error. A destructor is a method that de-allocates an object’s memory. We can write
code for a destructor, generally overriding the default Destroy destructor, to let the
object execute some code before it is destroyed. In your code, of course, you don’t
have to handle memory de-allocation—this is something the runtime library does
for you.

Destroy is a virtual destructor of the TObject class. Most of the classes that require
custom clean-up code when the objects are destroyed override this virtual method.
The reason you should never define a new destructor is that objects are usually
destroyed by calling the Free method, and this method calls the Destroy virtual
destructor (possibly the overridden version) for you.
As I’ve just mentioned, Free is simply a method of the TObject class, inherited by all
other classes. The Free method basically checks whether the current object (Self) is
not nil before calling the Destroy virtual destructor.


Be aware that Free does this:

procedure TObject.Free;
  if Self <> nil then