Day 10

This is the Day 10 page for computer programming course 101, an introduction to computer programming. Day 10 teaches the concept of complex user defined types.

Below are the topics and course materials we are learning today.

Complex Types

In our previous lessons we touched on intrinsic types such a String, Integer, Char, and Single. In out last session we discussed user defined such as type aliases, sub ranges, enumerations, and sets. All of these types reference a single piece of information generally of a fixed size. Complex types are types that are user defined with various sizes dependent upon how you define them.

Records

The first complex type we'll examine is the record. A record (called to a structure in some languages) represents a collection of various types. Each item in the collection is called a is called a field. The declaration of a record type specifies a name and type for each field. The syntax of a record type declaration is as follows:
type
  TRecordName = record
    Field1: TypeName1;
    Field2: TypeName2;
    Field3: TypeName3;
    ...
  end;
Where TRecordName is a valid identifier, Fieldn is a valid identifier or a comma-delimited list of identifiers, and each TypeName is a valid type. The record declaration terminates with the end keyword and a ; semicolon.

Record Example

For example, the following declaration creates a record type called TDateRec.
type
  TDateRec = record
    Year: Integer;
    Month: (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
    Day: 1..31;
  end;
Each TDateRec contains three fields: an Integer value called Year, a value of an enumerated type called Month, and another Integer between 1 and 31 called Day. The identifiers Year, Month, and Day are the field designators for TDateRec, and behave like variables.

Using a Record

The TDateRec type declaration, however, does not allocate any memory for the Year, Month, and Day fields. Memory is allocated when you declare a variable of type, like so:
var
  StartDate, FinishDate: TDateRec;
This variable declaration creates two instances of TDateRec, called StartDate and FinishDate. You can access the fields of a record by qualifying the fields within the record:
StartDate.Year := 1776;
StartDate.Month :=  Jul;
StartDate.Day := 4;
Or use may use a with statement:
with StartDate do
begin
  Year := 1776;
  Month := Jul;
  Day := 4;
end;
You can also copy the values of StartDate's fields to FinishDate:
FinishDate := StartDate;
FinishDate.Year := 2050;

Other Records

Here are a few example of other record types. Examine them and see if you can understand their meanings.
type
  TPoint = record
    X, Y: Integer;
  end;

  TRectangle = record
    X, Y, Width, Height: Integer;
  end;

  TSuit = (Diamonds, Clubs, Hearts, Spades);
  TRank = (Ace, Two, Three, Four, Five, Six,
    Seven, Eight, Nine, Ten, Jack, Queen, King);

  TCard = record
    Suit: TSuit;
    Rank: TRank;
    FaceDown: Boolean;
  end;

  TCard = record
    Suit: TSuit;
    Rank: TRank;
    FaceDown: Boolean;
  end;

  TAddress = record
    Street: string;
    City, State, ZipCode: string;
  end;

  TPerson = record
    Name: string;
    Birthday: TDateRec;
    Address: TAddress;
  end;

  TBusiness = record
    Name: string;
    StockSymbol: string;
    Headquarters: TAddress;
    ChiefExecutive: TPerson;
  end;

Arrays

Another complex type is the array type. An array represents an indexed collection of elements of the same type. The syntax of an array type declaration is as follows:
type
  TArrayName = array [LowBound..HighBound] of SomeType;
Where TArrayName is a valid identifier, LowBound and HighBound are Integers, and each SomeType is a valid type. The array declaration terminates with a ; semicolon.

Array Example

For example, the following declaration creates a array type called TDeck.
type
  TDeck = array [1..52] of TCard;
You can then make use of a TDeck like so
procedure BuildDeck(var Deck: TDeck);
const
  Range = Ord(High(TRank)) + 1;
var
  Deck: TDeck;
  I: Integer;
begin
  for I := Low(Deck) to High(Deck) do
  begin
    Deck[I].Suit := Low(TSuit);
    Deck[I].Rank := Low(TRank);
    Inc(Deck[I].Suit, (I - 1) div Range);
    Inc(Deck[I].Rank, (I - 1) mod Range);
    Deck[I].FaceDown := True;
  end;
end;

Array Boundaries

Arrays can have any upper and lower bounds. You set these bounds when you declare an array. For example:
type
  TDeck = array[1..52] of TCard;
Is just as valid as:
type
  TDeck = array[0..51] of TCard;
The only difference is in how you use them. In the first example an instance of a Deck[1] would retrieve the first card, while Deck[0] would retrieve the first card in the second example. Typically it makes more sense, and it is more common to use 0 are the lower bound, but in some situations you may want to make the lower bound a value other than 1.

Array Dimensions

The array examples we've look at so far are one dimensional arrays. That is, they are arrays with a single pair of upper and lower bounds. In most programming languages, and Pascal as well, you can define multi dimensional arrays.

Consider the following example:
type
  TDailyReminders = array[0..11, 0..31] of string;
We could use a two dimensional array like TDailyReminders to store a reminder for each day of the year. You could retrieve the day's reminder use code like:
Reminder := DailyReminders[Month, Day];
Note that the type within the array is always the same, in this case a string, and the indexers must always be an ordinal type.

Dynamic Arrays

Situations may arise where not know exactly how large to make an array. You may want to have the capability of changing the size of the array at runtime. A dynamic array declares an array with a type type, but no boundaries.
var
  Students: array of string;
The above code creates a one-dimensional dynamic array of strings. The declaration does not allocate memory for Students. To create the array in memory, we call SetLength procedure. For example, given the declaration above:
SetLength(Students, 14);
Allocates an array of 14 strings, indexed 0 to 13. Dynamic arrays are always integer-indexed, always starting from 0 to one less than their size in elements.

To create a two-dimensional dynamic array, use the following code:
type
  TMatrix = array of array of Double;
  
var
  Matrix: TMatrix;
begin
  SetLength(Matrix, 10, 20)
  // ...
end;
This allocates space for a two-dimensional, 10-by-20 array of Double floating-point values. To remove a dynamic array's memory space, assign nil to the array variable, like:
Matrix := nil;

Homework

There is no homework for day 10.

See also