Exercises: Generics

Part A: Conceptual Questions

A1. Explain the problem that generics solve. Why is writing separate TIntStack, TStringStack, and TExpenseStack classes undesirable?

A2. Compare generics with the Pointer-based TList approach. What are the three main advantages of generics?

A3. What is a type constraint? Why would you use T: class instead of leaving T unconstrained?

A4. Explain the difference between TFPGList<T> and TFPGObjectList<T>. When would you use each?

A5. What does "specialize" mean in the context of generics? Why does Free Pascal require the specialize keyword in {$mode objfpc}?

A6. Can a generic class have more than one type parameter? Give an example of when this would be useful.

A7. Why are generics described as having "zero runtime overhead"? What does the compiler do with a generic specialization?


Part B: Tracing and Prediction

B1. What is the output of this code?

type
  generic TPair<TFirst, TSecond> = record
    First: TFirst;
    Second: TSecond;
  end;

  TIntStringPair = specialize TPair<Integer, String>;

var
  P: TIntStringPair;
begin
  P.First := 42;
  P.Second := 'hello';
  WriteLn(P.First, ' ', P.Second);
end.

B2. Will this code compile? If not, why?

type
  generic TMinFinder<T> = class
    function FindMin(A, B: T): T;
  end;

function TMinFinder.FindMin(A, B: T): T;
begin
  if A < B then
    Result := A
  else
    Result := B;
end;

type
  TIntMin = specialize TMinFinder<Integer>;

B3. What is the output?

uses fgl;
type
  TIntList = specialize TFPGList<Integer>;
var
  List: TIntList;
  i: Integer;
begin
  List := TIntList.Create;
  try
    List.Add(30);
    List.Add(10);
    List.Add(50);
    List.Add(20);
    List.Sort;
    for i := 0 to List.Count - 1 do
      Write(List[i], ' ');
    WriteLn;
  finally
    List.Free;
  end;
end.

Part C: Short Programming Exercises

C1. Generic Pair Define a generic TPair<TKey, TValue> record with Key: TKey and Value: TValue fields. Write a generic function MakePair<TKey, TValue> that creates and returns a pair. Demonstrate with specialize TPair<String, Integer> to store name-age pairs.

C2. Generic Queue Implement a generic TQueue<T> class with Enqueue(AValue: T), function Dequeue: T, function Peek: T, function IsEmpty: Boolean, and Count property. Use a dynamic array with head and tail indices. Test with integers and strings.

C3. Generic Minimum and Maximum Write generic functions Min<T> and Max<T> that accept two values and a comparison function, and return the smaller or larger value. The comparison function should have type function(const A, B: T): Integer. Test with integers, strings, and dates.

C4. Generic Contains Write a generic function Contains<T>(const Arr: array of T; const Target: T; Equals: function(const A, B: T): Boolean): Boolean that searches an array for a value using a caller-provided equality function. Test with an array of records.

C5. Generic TFPGMap Usage Using TFPGMap<String, Integer>, write a program that reads words from a text file and counts the frequency of each word. Display the 10 most frequent words.


Part D: Design Challenges

D1. Generic Priority Queue Implement a generic TPriorityQueue<T> class where each item has a priority (integer). Items with higher priority are dequeued first. Items with equal priority follow FIFO order. Use a dynamic array of records containing Value: T and Priority: Integer. Test with a hospital emergency room scenario: patients with severity 1 (critical) through 5 (minor) are added, and the queue always serves the most critical patient first.

D2. Generic Observable List Combine generics with interfaces (from Chapter 18): create a generic TObservableList<T> that notifies registered observers whenever an item is added, removed, or changed. Define an IListObserver interface with OnItemAdded, OnItemRemoved, and OnItemChanged methods. Demonstrate with a list of expenses that automatically updates a budget tracker and a UI display whenever the list changes.

D3. Generic Repository Pattern Design a generic TRepository<T: class> that provides CRUD operations (Create/Read/Update/Delete) for any class type. Store items in a TFPGObjectList<T>. Add methods: Add(Item: T), GetByIndex(Index: Integer): T, Remove(Index: Integer), Count: Integer, FindAll(Predicate: function(Item: T): Boolean): TFPGObjectList<T>. Demonstrate with TRepository<TExpense> and TRepository<TContact>.