Extra 4
Extra 4
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;
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
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
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;
var
ADay: TMyDate;
begin
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