When defining parameters it’s possible to define them either as default (none), var, out or const. The difference between all these is the way the value is committed to the called function. The cue’s for this are:

– Call-by-reference
– Call-by-value

The above mentioned keywords (none, var, out, const) define the way variables are called:

// Call-by-value
procedure ParamDefault(AValue: Integer);

// Call-by-reference
procedure ParamVar(var AValue: Integer);
procedure ParamOut(out AValue: Integer);
procedure ParamConst(const AValue: Integer);

But why bothering defining parameters as call-by-reference?
By defining a parameter as call-by-reference it’s not the value that is committed, but the address of the value. This can be extremely useful, when the value itself is many times bigger than the pointer (pointer-sizes depend on the architecture).

So let’s look at an example using an Integer-parameter:

{ Call-by-value

Size of Integer is 32-Bit }
procedure CallByValue(AValue: Integer);

{ Call-by-reference

Size of Integer is:
 - 32-Bit system: 32-Bit
 - 64-Bit system: 64-Bit }
procedure CallByReference(const AValue: Integer);

In this example we can see that defining the parameter as call-by-reference it gets even worse. But when we take a type whose size is bigger it quickly becomes clear, why it’s sometimes better to use call-by-reference.

// Size of TSize = 96-Bit
TSize = record
  FWidth: Integer; // 32-Bit
  FHeight: Integer; // 32-Bit
  FDepth: Integer; // 32-Bit
end;

// Size of Sizes = 288-Bit (96-Bit * 3)
var
  Sizes: Array[0..2] of TSize;

Types like records (depending on the fields) and arrays can use quite a big amount of memory where it’s more efficient to use call-by-reference.

The same goes for String. String essentially is an object, but when you commit it to a function as parameter you don’t commit the address like with every other object. Instead it creates a copy of the String in the memory and commits the address.

So a general recommendation is, to use call-by-reference (var, out, const) for record-, array- and String-parameter whenever it’s possible to save memory and performance.

 

TL;DR

Use const/var/out parameters for Arrays, Records and Strings whenever it’s possible.

Ever wondered why your exe-File got so big after all the time you worked on it? Well, for that reason the map-file actually exists, but it’s not really easy to understand. Lines and lines of non-human-readable lines of debug text…
Wouldn’t it be great if there was a tool to parse it? That was at least what I was thinking. After searching and not finding anything the answer either was “There is not tool” or “You don’t know how to search”. Positively thinking it was the first I started making my own parser for map-files, so here’s the result of my short work to quickly find unnecessary units in my application.

DSMapParser

The tool (called DSMapParser) is quite simple in what it’s doing. You compile your project with a map file and open the map-file in the Map Parser.
The parser than (surprise!) parses the map-file and groups every file by its namespace. The result is a quite nice overview of all the units that bloat your application.

DSMapParser

Installation

  1. Grab the latest release from the github repository: https://github.com/delphi-sucks/DSMapParser/releases
  2. Extract it and use it! That simple!

Source: https://github.com/delphi-sucks/DSMapParser

Using it

Before you can actually use the map-parser you probably need to adjust some settings in your project to generate a map-file:

  1. Go to your project options: Project > Options
  2. Navigate to “Delphi-Compiler > Linking”
  3. Change the setting “Map-File” to “Segments”

Ensure that you have changed the options in your corresponding release-configuration.

After changing these settings your compiler creates beside your .exe-file also a .map-file, which can be used by the Map-Parser.

 

TL;DR

Parse your Map-File with the DSMapParser to find out why your application is so bloated.