Exercises: Advanced Object Pascal

Part A: Conceptual Questions

A1. When is operator overloading appropriate, and when is it a bad idea? Give two examples of types where operator overloading makes code clearer and two examples where it would make code confusing.

A2. What is a class helper? How does it differ from inheritance? What are its limitations?

A3. Explain what a closure is and how it differs from a regular function. Why is the ability to "capture" variables from the enclosing scope powerful?

A4. What is RTTI? When should you use it, and when should you prefer compile-time type checking?

A5. Explain the fluent interface pattern. What does a fluent method return, and why?

A6. The chapter emphasizes "taste and restraint." In your own words, explain what this means for advanced features. How do you decide whether to use an advanced feature or stick with simpler constructs?

A7. Compare anonymous functions in Pascal with lambdas in Python or arrow functions in JavaScript. What are the similarities and differences?


Part B: Tracing and Prediction

B1. What is the output?

type
  TPoint = record
    X, Y: Double;
    class operator + (const A, B: TPoint): TPoint;
    function ToString: String;
  end;

class operator TPoint.+(const A, B: TPoint): TPoint;
begin
  Result.X := A.X + B.X;
  Result.Y := A.Y + B.Y;
end;

function TPoint.ToString: String;
begin
  Result := Format('(%.1f, %.1f)', [X, Y]);
end;

var
  A, B, C: TPoint;
begin
  A.X := 1; A.Y := 2;
  B.X := 3; B.Y := 4;
  C := A + B;
  WriteLn(C.ToString);
end.

B2. Will the following compile? If not, why?

type
  TIntHelper = record helper for Integer;
    function IsEven: Boolean;
  end;

function TIntHelper.IsEven: Boolean;
begin
  Result := Self mod 2 = 0;
end;

var N: Integer = 42;
begin
  WriteLn(N.IsEven);
end.

B3. What is the output of this anonymous function example?

{$modeswitch anonymousfunctions}
type
  TIntFunc = function(X: Integer): Integer;

function MakeMultiplier(Factor: Integer): TIntFunc;
begin
  Result := function(X: Integer): Integer
  begin
    Result := X * Factor;
  end;
end;

var
  Triple, Quintuple: TIntFunc;
begin
  Triple := MakeMultiplier(3);
  Quintuple := MakeMultiplier(5);
  WriteLn(Triple(4));
  WriteLn(Quintuple(4));
  WriteLn(Triple(10) + Quintuple(2));
end.

Part C: Short Programming Exercises

C1. TVector2D with Operators Create a TVector2D record with X, Y: Double fields. Overload + (vector addition), - (vector subtraction), * (scalar multiplication), and = (equality). Add a Magnitude function and a ToString function. Write a main program demonstrating all operations.

C2. TFraction with Operators Create a TFraction record with Numerator, Denominator: Integer fields. Overload +, -, *, /, =, <, and >. Implement automatic simplification (GCD reduction) after every operation. Add a ToString function that displays "3/4" format.

C3. Integer Helper Write a record helper for Integer with methods: - IsEven, IsOdd: Boolean checks - IsPrime: Primality check - Factorial: Compute factorial (raise exception if negative) - ToBinary: Return the binary representation as a String - Clamp(Min, Max: Integer): Return the value clamped to the range

C4. String Analysis Helper Write a class helper for String with methods: - WordCount: Count the number of words - Reverse: Return the reversed string - IsPalindrome: Check if the string is a palindrome (ignoring case and spaces) - CountChar(C: Char): Count occurrences of a character - RemoveVowels: Return the string with vowels removed

C5. Anonymous Functions for Sorting Using an expense list, write a program that sorts expenses by different criteria using anonymous functions passed to a generic sort procedure. Sort by: amount ascending, amount descending, category alphabetically, and date (newest first). Display each sorted result.


Part D: Design Challenges

D1. Expression Evaluator Build a simple mathematical expression evaluator using operator overloading. Create a TExpression type that can represent constants, addition, subtraction, multiplication, and division. Overload operators so you can write:

var A, B, C, Result: TExpression;
begin
  A := Expr(3);
  B := Expr(4);
  C := Expr(5);
  Result := (A + B) * C;
  WriteLn(Result.Evaluate);  { 35 }
  WriteLn(Result.ToString);  { (3 + 4) * 5 }
end;

D2. Fluent Test Framework Design a simple testing framework with a fluent interface:

Test('Addition')
  .Given(2 + 2)
  .ShouldEqual(4);

Test('String length')
  .Given(Length('Hello'))
  .ShouldEqual(5);

Test('List empty')
  .Given(List.Count)
  .ShouldEqual(0);

Implement the Test function, the TTestCase class with Given, ShouldEqual, ShouldBeGreaterThan, ShouldBeLessThan, and ShouldNotEqual methods. Print pass/fail results.

D3. PennyWise Report Builder Combine fluent interfaces, anonymous functions, and operator overloading to build a PennyWise report builder:

Report.Create
  .Title('Monthly Summary')
  .Filter(function(E: TExpense): Boolean begin Result := E.Amount > Money(10.00); end)
  .GroupBy('Category')
  .SortBy('Amount', Descending)
  .Format('Text')
  .Generate('report.txt');

Implement enough of this to produce a working text report from a list of sample expenses.