0% found this document useful (0 votes)
4 views

Extra 4

Uploaded by

skamelrech2020
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

Extra 4

Uploaded by

skamelrech2020
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 4

130 - 05: Arrays and Records

The following are the data types supported in a type-variant open array value and by
the TVarRec record:
vtInteger vtBoolean vtChar
vtExtended vtString vtPointer
vtPChar vtObject vtClass
vtWideChar vtPWideChar vtAnsiString
vtCurrency vtVariant vtInterface
vtWideString vtInt64 vtUnicodeString
The record structure has a field with the type (VType) and variant field you can use
to access the actual data (more about records in a few pages, even if this is an
advanced usage for that construct).
A typical approach is to use a case statement to operate on the different types of
parameters you can receive in such a call. In the SumAll function example, I want to
be able to sum values of different types, transforming strings to integers, characters
to the corresponding ordinal value, and adding 1 for True Boolean values. The code
is certainly quite advanced (and it uses pointer dereferences), so don't worry if you
don't fully understand it for now:
function SumAll (const Args: array of const): Extended;
var
I: Integer;
begin
Result := 0;
for I := Low(Args) to High (Args) do
case Args [I].VType of
vtInteger:
Result := Result + Args [I].VInteger;
vtBoolean:
if Args [I].VBoolean then
Result := Result + 1;
vtExtended:
Result := Result + Args [I].VExtended^;
vtWideChar:
Result := Result + Ord (Args [I].VWideChar);
vtCurrency:
Result := Result + Args [I].VCurrency^;
end; // case
end;
I've added this function to the OpenArray application project, which calls it as fol-
lows:
var
X: Extended;
Y: Integer;
begin
Y := 10;
X := SumAll ([Y * Y, 'k', True, 10.34]);
Show ('SumAll: ' + X.ToString);
end;

Marco Cantù, Object Pascal Handbook


05: Arrays and Records - 131

The output of this call adds the square of Y, the ordinal value of K (which is 107), 1
for the Boolean value, and the extended number, resulting in:
SumAll: 218.34

Record Data Types


While arrays define lists of identical items referenced by a numerical index, records
define groups of elements of different types referenced by name. In other words, a
record is a list of named items, or fields, each with a specific data type. The defini-
tion of a record type lists all these fields, giving each field a name used to refer to it.

note Records are available in most programming languages. They are defined with the struct keyword
in the C language, while C++ has an extended definition including methods, much like Object Pas-
cal has. Some more “pure” object-oriented languages have only the notion of class, not that of a
record or structure.

Here is a small code snippet (from the RecordsDemo application project) with the
definition of a record type, the declaration of a variable of that type, and few state-
ments using this variable:
type
TMyDate = record
Year: Integer;
Month: Byte;
Day: Byte;
end;

var
BirthDay: TMyDate;
begin
BirthDay.Year := 1997;
BirthDay.Month := 2;
BirthDay.Day := 14;
Show ('Born in year ' + BirthDay.Year.ToString);

note The term records is at times used in a rather loose way to refer to two different elements of the
language: a record type definition and a variable of record type (or record instance). Record is
used as a synonym of both record type and record instance, unlike for class types in which case
the instance is called object.

There is way more to this data structure in Object Pascal than a simple list of fields,
as the remaining part of this chapter will illustrate, but let's start with this tradi-
tional approach to records. The memory for a record is generally allocated on the

Marco Cantù, Object Pascal Handbook


132 - 05: Arrays and Records

stack for a local variable and in the global memory for a global one. This is high-
lighted by a call to SizeOf, which returns the number of bytes required by a variable
or type, like in this statement:
Show ('Record size is ' + SizeOf (BirthDay).ToString);
which returns 8 (why it does return 8 and not 6, 4 bytes for the Integer and two for
each byte field, I'll discuss in the section “Fields Alignments”).
In other words, records are value types. This implies that if you assign a record to
another, you are making a full copy. If you make a change to a copy, the original
record won't be affected. This code snippets explains the concept in code terms:
var
BirthDay: TMyDate;
ADay: TMyDate;
begin
BirthDay.Year := 1997;
BirthDay.Month := 2;
BirthDay.Day := 14;

ADay := Birthday;
ADay.Year := 2008;

Show (MyDateToString (BirthDay));


Show (MyDateToString (ADay));
The output (in Japanese or international date format) is:
1997.2.14
2008.2.14
The same copy operation takes place when you pass a record as parameter to a func-
tion, like in the MyDateToString I used above:
function MyDateToString (MyDate: TMyDate): string;
begin
Result := MyDate.Year.ToString + '.' +
MyDate.Month.ToString + '.' +
MyDate.Day.ToString;
end;
Each call to this function involves a complete copy of the record's data. To avoid the
copy, and to possibly make a change to the original record you have to explicitly use
a reference parameter. This is highlighted by the following procedure, that makes
some changes to a record passed as parameter:
procedure IncreaseYear (var MyDate: TMyDate);
begin
Inc (MyDate.Year);
end;

var
ADay: TMyDate;
begin

Marco Cantù, Object Pascal Handbook


05: Arrays and Records - 133

ADay.Year := 2016;
ADay.Month := 3;
ADay.Day := 18;

Increaseyear (ADay);
Show (MyDateToString (ADay));
Given the Year field of the original record value is increased by the procedure call,
the final output is one year later than the input:
2017.3.18

Using Arrays of Records


As I mentioned, arrays represent a data structure repeated several times, while
records a single structure with different elements. Given these two type constructors
are orthogonal, it is very common to use them together, defining arrays of records
(while it is possible but uncommon to see records of arrays).
The array code is just like that of any other array, with each array element taking the
size of the specific record type. While we'll see later how to use more sophisticated
collection or container classes (for lists of elements), there is a lot in terms of data
management you can achieve with arrays of records.
In the RecordsTest application project I've added an array of the TMyDate type,
which can be allocated, initialized and used with code like the following:
var
DatesList: array of TMyDate;
I: Integer;
begin
// allocate array elements
SetLength (DatesList, 5);

// assign random values


for I := Low(DatesList) to High(DatesList) do
begin
DatesList[I].Year := 2000 + Random (50);
DatesList[I].Month := 1 + Random (12);
DatesList[I].Day := 1 + Random (27);
end;

// display the values


for I := Low(DatesList) to High(DatesList) do
Show (I.ToString + ': ' +
MyDateToString (DatesList[I]));
Given the app uses random data, the output will be different every time, and could
be like the following I've captured:
0: 2014.11.8

Marco Cantù, Object Pascal Handbook

You might also like