Hello World & Running
Hello, World
program HelloWorld;
begin
writeln('Hello, World!');
end. puts "Hello, World!" Ruby has no
program header, no begin/end. wrapper, and no compilation step. Top-level code runs top to bottom the moment the file is loaded. puts writes its argument followed by a newline — the everyday equivalent of writeln.Compiling vs running
{ Pascal is compiled ahead of time:
fpc hello.pas && ./hello
Optimised build:
fpc -O2 hello.pas
The result is a standalone native binary
with no runtime dependency. } # Ruby is interpreted — no build step, no binary:
# ruby hello.rb
#
# Run a one-liner straight from the shell:
# ruby -e 'puts "Hello, World!"'
puts "Ruby runs the source directly" Free Pascal compiles to a native executable you ship on its own. Ruby ships the source and interprets it at run time — there is no separate compile phase, and the script you edit is exactly the program that runs. The trade is portability and edit-run speed against the native performance and standalone binary you get from
fpc.Comments
program Comments;
begin
{ This is a brace comment }
(* This is an old-style comment *)
// This is a line comment
writeln('Comments shown above');
end. # This is a line comment — the only everyday kind.
=begin
This is a block comment, rarely used.
It must start in column one.
=end
puts "Comments shown above" Ruby has a single line-comment character,
#, used for everything. Its block-comment form (=begin/=end) exists but is rare — Rubyists simply prefix each line with #. There is no equivalent of Pascal's three interchangeable comment styles.Formatted output
program PrintFormat;
uses SysUtils;
var
name: string;
age: integer;
pi: double;
begin
name := 'Alice';
age := 30;
pi := 3.14159;
writeln(Format('Name: %s, Age: %d, Pi: %.2f', [name, age, pi]));
writeln(name, ' is ', age, ' years old');
end. name = "Alice"
age = 30
pi = 3.14159
puts format("Name: %s, Age: %d, Pi: %.2f", name, age, pi)
puts "#{name} is #{age} years old" Ruby's
format (also written "...".%(...)) uses the same %s/%d/%.2f specifiers as Pascal's Format. But the idiomatic way to build a string is interpolation: #{...} inside a double-quoted string evaluates any expression and inserts its value. There is no uses SysUtils to add — these are built in.Variables & Types
Variables — no declarations
program Variables;
var
count: integer;
message: string;
ratio: double;
flag: boolean;
begin
count := 42;
message := 'hello';
ratio := 3.14;
flag := true;
writeln(count, ' ', message, ' ', ratio:0:2, ' ', flag);
end. count = 42
message = "hello"
ratio = 3.14
flag = true
puts "#{count} #{message} #{ratio} #{flag}" Ruby has no
var block and no type annotations. A variable springs into existence the first time you assign to it, and it can hold any object — an integer now, a string later. Assignment is plain =, not Pascal's :=; Ruby reserves = for assignment and == for comparison, so the two can never be confused.Dynamic typing
program DynamicTyping;
var
value: integer;
begin
value := 42;
{ A Pascal variable's type is fixed at compile time.
value := 'hello'; <- compile error: incompatible types }
writeln(value);
writeln('Type is fixed at compile time');
end. value = 42
puts value.class # Integer
value = "hello" # legal — the variable is just a name
puts value.class # String
value = [1, 2, 3]
puts value.class # Array In Pascal a variable is its type — the compiler binds the two and rejects any mismatch. In Ruby a variable is only a name that points at an object, and the same name may point at objects of different classes over its life. Every object carries its own class, which you can ask for at any time with
.class.Everything is an object
program Primitives;
begin
{ In Pascal, an integer is a raw machine value.
You cannot call a method on it. }
writeln(Abs(-5)); { stand-alone function }
writeln(Sqr(4)); { stand-alone function }
writeln(42);
end. # In Ruby, 42 is a full object with methods:
puts(-5.abs) # 5
puts 4 ** 2 # 16
puts 42.even? # true
puts 42.class # Integer
puts 42.is_a?(Numeric) # true There are no primitives in Ruby. Integers, floats, booleans, and even
nil are objects with classes and methods — (-5).abs, 42.even?, 3.times. Where Pascal offers stand-alone functions like Abs and Sqr that take a value, Ruby sends a message to the value itself. This single rule — everything is an object — shapes the entire language.Constants
program Constants;
const
MAX_SIZE = 100;
PI = 3.14159265;
GREETING = 'Hello';
begin
writeln('Max: ', MAX_SIZE);
writeln('Pi: ', PI:0:8);
writeln(GREETING);
end. MAX_SIZE = 100
PI = 3.14159265
GREETING = "Hello"
puts "Max: #{MAX_SIZE}"
puts "Pi: #{PI}"
puts GREETING
# Reassigning only warns — Ruby constants are a convention:
# MAX_SIZE = 200 # warning: already initialized constant Ruby marks a constant by capitalising its first letter — any identifier starting with an uppercase letter is a constant, and that includes every class and module name. Unlike Pascal's
const, the value is not truly immutable: reassigning it merely prints a warning. The capital letter signals intent rather than enforcing it.nil vs Pascal nil
program NilValue;
type
PInteger = ^integer;
var
pointer: PInteger;
begin
pointer := nil; { nil is only for pointers }
if pointer = nil then
writeln('Pointer is nil');
{ Plain integers and strings can never be nil. }
end. value = nil # any variable can hold nil
puts value.nil? # true
puts value.class # NilClass — nil is an object too!
puts value.inspect # nil
# nil and false are the ONLY falsy values:
puts "falsy" unless value
puts "zero is truthy" if 0 Pascal's
nil is strictly a null pointer; ordinary values can never be nil. Ruby's nil is a universal "no value" that any variable may hold, and it is itself an object (the sole instance of NilClass) with methods like .nil?. Crucially, only nil and false are falsy — 0 and the empty string are both truthy, unlike in many other languages.Strings
String basics
program StringBasics;
var
greeting: string;
name: string;
full: string;
begin
greeting := 'Hello';
name := 'Alice';
full := greeting + ', ' + name + '!';
writeln(full);
writeln(Length(full));
end. greeting = "Hello"
name = "Alice"
full = "#{greeting}, #{name}!" # interpolation
puts full
puts full.length # method on the string itself A Ruby string is a full object that knows its own length:
full.length, not Length(full). Concatenation with + works as in Pascal, but interpolation ("#{greeting}, #{name}!") is the idiomatic way to assemble text. Single-quoted strings are literal; only double-quoted strings interpolate and honour escapes like \n.String operations
program StringOps;
uses SysUtils;
var
text: string;
begin
text := ' Hello, World! ';
writeln(Trim(text));
writeln(UpperCase(text));
writeln(LowerCase(text));
writeln(Pos('World', text));
writeln(Copy(text, 3, 5));
end. text = " Hello, World! "
puts text.strip # Trim
puts text.upcase # UpperCase
puts text.downcase # LowerCase
puts text.index("World") # zero-based position (or nil)
puts text.strip[0, 5] # substring: start, length Where Pascal calls
SysUtils functions on a string (Trim(text), UpperCase(text)), Ruby calls methods on the string (text.strip, text.upcase). The method library is enormous and chainable: text.strip.upcase.reverse. Note index returns a zero-based offset or nil if not found, where Pascal's Pos returns a one-based position or 0.Mutable strings & frozen literals
program StringMutation;
var
text: string;
begin
text := 'Hello';
text := text + ' World'; { builds a new string }
text[1] := 'J'; { in-place: 1-based index }
writeln(text); { Jello World }
end. # String literals are frozen in Ruby 4.0.
# Use unary + (or .dup) for a mutable copy:
text = +"Hello"
text << " World" # << appends in place
text[0] = "J" # zero-based index assignment
puts text # Jello World Ruby strings are mutable objects, and like Pascal you can assign to an individual character — but Ruby indexes from zero. As of Ruby 4.0 string literals are frozen by default, so mutating one raises
FrozenError; prefix the literal with unary + (or call .dup) to get a fresh mutable copy. The << operator appends in place, avoiding the new-string allocation that Pascal's + performs.Splitting & joining
program SplitJoin;
uses Classes;
var
parts: TStringList;
index: integer;
begin
parts := TStringList.Create;
try
parts.Delimiter := ',';
parts.StrictDelimiter := True;
parts.DelimitedText := '1,2,3,4';
for index := 0 to parts.Count - 1 do
write(parts[index], ' ');
writeln;
parts.Delimiter := '-';
writeln(parts.DelimitedText);
finally
parts.Free;
end;
end. parts = "1,2,3,4".split(",")
puts parts.inspect # ["1", "2", "3", "4"]
parts.each { |word| print word, " " }
puts
puts parts.join("-") # 1-2-3-4 Both languages split a string into pieces on a delimiter and join them back. In Ruby,
split and join are methods on the string and array respectively, and the resulting array is a first-class object you can immediately iterate with a block. Free Pascal has no string-array literal type, so the conventional route is a TStringList whose DelimitedText property both parses and reassembles a delimited string.Regular expressions
program RegexDemo;
uses RegExpr;
var
matcher: TRegExpr;
begin
matcher := TRegExpr.Create('\d+');
try
if matcher.Exec('abc123def456') then
writeln('First match: ', matcher.Match[0]);
finally
matcher.Free;
end;
end. text = "abc123def456"
# Regex literals are built into the language: /.../
if text =~ /\d+/
puts "First match: #{$~[0]}"
end
puts text.scan(/\d+/).inspect # ["123", "456"] Regular expressions are part of Ruby's syntax, written between slashes (
/\d+/) with no library to import and no object to create and free. The =~ operator tests a match; scan returns every match as an array. Compare the RegExpr unit in Pascal, where you create a TRegExpr, call Exec, and must Free it in a finally block.Numbers
Integers — one type, no overflow
program IntTypes;
var
small: shortint; { 8-bit }
medium: integer; { 32-bit }
large: int64; { 64-bit }
begin
small := 127;
medium := 2000000;
large := 9000000000;
writeln(small, ' ', medium, ' ', large);
{ Exceeding int64 overflows silently. }
end. small = 127
medium = 2_000_000
large = 9_000_000_000
puts "#{small} #{medium} #{large}"
# Integers grow without limit — no overflow:
huge = 2 ** 200
puts huge
puts huge.class # Integer Ruby has a single
Integer type with arbitrary precision: when a value exceeds machine-word size, Ruby transparently switches to a bignum representation, so 2 ** 200 is exact. There is no shortint/integer/int64 ladder to choose from and no silent overflow to guard against. Underscores may be used as digit separators, just as in Pascal.Integer vs float division
program Division;
var
a, b: integer;
begin
a := 7;
b := 2;
writeln(a div b); { integer division: 3 }
writeln(a mod b); { remainder: 1 }
writeln(a / b:0:4); { real division: 3.5000 }
end. a = 7
b = 2
puts a / b # 3 — integer / integer is integer division
puts a % b # 1 — remainder
puts a.fdiv(b) # 3.5 — force float division
puts a.to_f / b # 3.5 — or convert first Ruby has no separate
div operator: / performs integer division when both operands are integers (so 7 / 2 is 3) and float division when either is a float. This catches Pascal programmers who expect / to always yield a real. Use .fdiv or convert one operand with .to_f to force a floating-point result; % is the remainder, like mod.Math functions
program MathFns;
uses Math;
begin
writeln(Sqrt(2.0):0:6);
writeln(Power(2.0, 10.0):0:0);
writeln(Round(3.7));
writeln(Trunc(3.7));
writeln(Abs(-5));
end. puts Math.sqrt(2) # 1.4142135623730951
puts 2 ** 10 # 1024 — exponent operator
puts 3.7.round # 4
puts 3.7.to_i # 3 — truncate toward zero
puts(-5.abs) # 5 Trigonometric and transcendental functions live in the
Math module (Math.sqrt, Math.sin), parallel to Pascal's Math unit. But rounding and absolute value are methods on the number itself: 3.7.round, (-5).abs. Exponentiation has a dedicated operator, **, rather than a Power function.Arrays
Array literals
program ArrayBasics;
var
numbers: array[0..4] of integer;
index: integer;
begin
numbers[0] := 10;
numbers[1] := 20;
numbers[2] := 30;
numbers[3] := 40;
numbers[4] := 50;
for index := 0 to High(numbers) do
write(numbers[index], ' ');
writeln;
end. numbers = [10, 20, 30, 40, 50]
puts numbers[0] # 10
puts numbers[-1] # 50 — negative indexes count from the end
puts numbers.length # 5
puts numbers.inspect # [10, 20, 30, 40, 50] A Ruby array is written as a literal in square brackets and grows on demand — no fixed bounds, no
SetLength. It can hold objects of mixed classes. Indexing is zero-based like a C-mode Pascal array, and negative indexes count back from the end (numbers[-1] is the last element), a convenience Pascal lacks.Growing an array
program DynArray;
var
numbers: array of integer;
index: integer;
begin
SetLength(numbers, 0);
for index := 1 to 5 do
begin
SetLength(numbers, Length(numbers) + 1);
numbers[High(numbers)] := index * 10;
end;
writeln('Length: ', Length(numbers));
end. numbers = []
(1..5).each { |index| numbers << index * 10 }
puts "Length: #{numbers.length}"
puts numbers.inspect # [10, 20, 30, 40, 50]
numbers.push(60, 70) # push multiple
puts numbers.last # 70 Ruby arrays resize themselves:
numbers << value (or push) appends in place, with no SetLength call and no manual High bookkeeping. Because the runtime manages the backing storage and a garbage collector reclaims it, the explicit grow-by-one pattern that Pascal forces simply disappears.Transforming with map & select
program ArrayTransform;
const
numbers: array[1..5] of integer = (1, 2, 3, 4, 5);
var
doubled: array[1..5] of integer;
index: integer;
begin
for index := 1 to 5 do
doubled[index] := numbers[index] * 2;
for index := 1 to 5 do
write(doubled[index], ' ');
writeln;
end. numbers = [1, 2, 3, 4, 5]
doubled = numbers.map { |number| number * 2 }
puts doubled.inspect # [2, 4, 6, 8, 10]
evens = numbers.select { |number| number.even? }
puts evens.inspect # [2, 4]
total = numbers.reduce(0) { |sum, number| sum + number }
puts total # 15 This is the single biggest shift for a Pascal programmer. Instead of an index loop that builds a result array element by element, Ruby gives every collection higher-order methods:
map transforms each element, select keeps those matching a condition, and reduce folds the collection to one value. The { |number| ... } is a block — a chunk of behaviour passed to the method.Slicing & combining
program ArraySlice;
var
numbers: array[0..5] of integer;
index: integer;
begin
for index := 0 to 5 do
numbers[index] := index;
{ No built-in slice — copy a range manually. }
for index := 1 to 3 do
write(numbers[index], ' ');
writeln;
end. numbers = [0, 1, 2, 3, 4, 5]
puts numbers[1..3].inspect # [1, 2, 3] — range slice
puts numbers[1, 2].inspect # [1, 2] — start, length
puts numbers.first(2).inspect # [0, 1]
puts (numbers + [6, 7]).inspect # concatenate
puts numbers.reverse.inspect # [5, 4, 3, 2, 1, 0] Ruby slices an array with a range (
numbers[1..3]) or a start/length pair (numbers[1, 2]), returning a new array. Arrays support + to concatenate, - to subtract elements, & for intersection, and dozens of query methods — operations that in Pascal you would write out by hand with index loops.Hashes & Dictionaries
Hashes vs TDictionary
program HashBasics;
uses Generics.Collections;
var
ages: specialize TDictionary<string, integer>;
begin
ages := specialize TDictionary<string, integer>.Create;
try
ages.Add('Alice', 30);
ages.Add('Bob', 25);
writeln('Alice is ', ages['Alice']);
writeln('Count: ', ages.Count);
finally
ages.Free;
end;
end. ages = { "Alice" => 30, "Bob" => 25 }
puts "Alice is #{ages["Alice"]}"
puts "Count: #{ages.size}"
ages["Carol"] = 28 # add a pair
puts ages.key?("Bob") # true
puts ages.inspect Ruby's
Hash is the built-in key-value map, written as a literal with => between key and value. There is no generic type parameter to specialise, no Create, and no Free — the garbage collector owns it. Keys and values may be any objects, and a hash literal is as ordinary as an array literal, where Pascal needs the Generics.Collections unit and an explicit TDictionary.Symbol keys
program HashSymbols;
uses Generics.Collections;
var
config: specialize TDictionary<string, string>;
begin
config := specialize TDictionary<string, string>.Create;
try
config.Add('host', 'localhost');
config.Add('port', '8080');
writeln(config['host'], ':', config['port']);
finally
config.Free;
end;
end. # Symbols (:name) are the idiomatic hash key:
config = { host: "localhost", port: "8080" }
puts "#{config[:host]}:#{config[:port]}"
# :host is a Symbol — an immutable, interned identifier:
puts :host.class # Symbol
puts config.keys.inspect # [:host, :port] Ruby has a type with no Pascal analogue: the symbol, written
:name. A symbol is an immutable, interned identifier — the same :host is one shared object everywhere it appears, which makes symbols ideal, memory-cheap hash keys. The { host: "..." } shorthand is sugar for { :host => "..." }. Think of a symbol as a name used as a value.Iterating a hash
program HashIterate;
uses Generics.Collections;
var
ages: specialize TDictionary<string, integer>;
pair: specialize TPair<string, integer>;
begin
ages := specialize TDictionary<string, integer>.Create;
try
ages.Add('Alice', 30);
ages.Add('Bob', 25);
for pair in ages do
writeln(pair.Key, ' => ', pair.Value);
finally
ages.Free;
end;
end. ages = { "Alice" => 30, "Bob" => 25 }
ages.each do |name, age|
puts "#{name} => #{age}"
end
# Hashes preserve insertion order in Ruby:
puts ages.map { |name, age| "#{name}:#{age}" }.join(", ") Iterating a hash yields each key and value straight into the block's two parameters —
|name, age| — with no TPair wrapper to unpack. Ruby hashes also guarantee insertion order when iterated, which Pascal's TDictionary does not promise. And the same map/select/reduce family that works on arrays works on hashes too.Default values
program HashDefault;
uses Generics.Collections;
var
counts: specialize TDictionary<string, integer>;
existing: integer;
begin
counts := specialize TDictionary<string, integer>.Create;
try
if not counts.TryGetValue('apple', existing) then
existing := 0;
counts.AddOrSetValue('apple', existing + 1);
writeln(counts['apple']);
finally
counts.Free;
end;
end. # A Hash can carry a default for missing keys:
counts = Hash.new(0)
"apple banana apple cherry apple".split.each do |fruit|
counts[fruit] += 1
end
puts counts.inspect # {"apple"=>3, "banana"=>1, "cherry"=>1} Passing a default to
Hash.new(0) makes every missing key read back as 0 instead of nil, so the classic count-the-occurrences loop becomes a one-liner counts[fruit] += 1. In Pascal you must TryGetValue and supply the fallback yourself on every access — Ruby folds that into the hash itself.Sets & Ranges
Sets — built in vs require
program SetType;
type
TColor = (Red, Green, Blue, Yellow);
TColors = set of TColor;
var
chosen: TColors;
begin
chosen := [Red, Blue];
if Red in chosen then
writeln('Red is chosen');
Include(chosen, Green);
chosen := chosen - [Blue];
writeln(Green in chosen, ' ', Blue in chosen);
end. require "set"
chosen = Set[:red, :blue]
puts chosen.include?(:red) # true
chosen << :green # add
chosen.delete(:blue) # remove
puts chosen.include?(:green) # true
puts chosen.include?(:blue) # false
puts (Set[1, 2, 3] & Set[2, 3, 4]).inspect # intersection Here Pascal is the more elegant language:
set of is a first-class type with in, +, -, and * operators built straight into the syntax. Ruby keeps Set in the standard library, so you require "set" first; thereafter it offers include?, & (intersection), | (union), and - (difference). Pascal's sets are bit-packed and limited to small ordinal types; Ruby's hold any objects.Ranges
program RangeType;
type
TMonth = 1..12;
var
month: TMonth;
index: integer;
begin
{ A subrange is a TYPE constraint, checked with {$R+}. }
for index := 1 to 12 do
write(index, ' ');
writeln;
month := 6;
writeln('Month: ', month);
end. months = 1..12 # a Range object
puts months.include?(6) # true
puts months.to_a.inspect # [1, 2, ... 12]
puts months.sum # 78
# Ranges work on more than integers:
puts ("a".."e").to_a.inspect # ["a", "b", "c", "d", "e"]
(1...5).each { |n| print n, " " } # ... excludes the end
puts A Pascal subrange like
1..12 is a compile-time type that constrains a variable. A Ruby Range like 1..12 is a runtime object you can iterate, test with include?, convert to an array, or sum. Two dots include the endpoint; three dots (1...5) exclude it. Ranges also span characters and other comparable objects, not just integers.Control Flow
if / elsif / else
program IfElse;
var
score: integer;
begin
score := 75;
if score >= 90 then
writeln('A')
else if score >= 80 then
writeln('B')
else if score >= 70 then
writeln('C')
else
writeln('F');
end. score = 75
if score >= 90
puts "A"
elsif score >= 80 # note the spelling: elsif
puts "B"
elsif score >= 70
puts "C"
else
puts "F"
end Ruby's conditional needs no
then and no parentheses around the condition, and it closes with a single end rather than relying on statement nesting. The chained keyword is elsif — one word, no second e — which trips up newcomers. Any block (if, while, def, class) terminates with end, Ruby's universal equivalent of Pascal's begin/end pairs.Statement modifiers
program ModifierIf;
var
age: integer;
begin
age := 20;
if age >= 18 then
writeln('Adult');
{ Pascal always needs the full if/then statement. }
end. age = 20
puts "Adult" if age >= 18 # trailing if
puts "Minor" unless age >= 18 # unless = if not
# A whole loop can trail too:
print "go " while (age -= 5) > 0
puts Ruby lets you append
if, unless, or while to the end of a statement — puts "Adult" if age >= 18 reads almost like English and is the preferred form for a one-line guard. unless is simply if not, with no Pascal counterpart. There is no equivalent in Pascal, where every conditional must be a full if...then statement.case / when
program CaseOf;
var
day: integer;
begin
day := 3;
case day of
1: writeln('Monday');
2: writeln('Tuesday');
3: writeln('Wednesday');
6, 7: writeln('Weekend');
else
writeln('Other');
end;
end. day = 3
result =
case day
when 1 then "Monday"
when 2 then "Tuesday"
when 3 then "Wednesday"
when 6, 7 then "Weekend"
else "Other"
end
puts result Ruby's
case/when mirrors Pascal's case/of — multiple values per branch (when 6, 7), an else fallback, and no fall-through. Two differences matter: each branch compares with the === operator (so a when can match a range, class, or regex, not just a constant), and the whole case is an expression that returns a value you can assign directly.case matching on class & range
program CaseClass;
var
value: integer;
begin
value := 42;
{ Pascal case only matches ordinal constants;
you cannot switch on a type or a range expression
the way Ruby can. }
case value of
0..9: writeln('single digit');
10..99: writeln('two digits');
else
writeln('big');
end;
end. value = 42
description =
case value
when 0..9 then "single digit"
when 10..99 then "two digits"
when Integer then "big integer"
when String then "some text"
else "unknown"
end
puts description Because
when uses ===, a Ruby case can match a range (0..9), a class (Integer tests whether the value is an integer), or a regular expression — all in the same statement. Pascal's case supports range labels too, but it can only ever branch on ordinal constants; it has no way to ask "is this value of this type?" at runtime.Loops & Iteration
Counting loops
program ForLoop;
var
index: integer;
begin
for index := 1 to 5 do
write(index, ' ');
writeln;
for index := 5 downto 1 do
write(index, ' ');
writeln;
end. (1..5).each { |index| print index, " " }
puts
5.downto(1) { |index| print index, " " }
puts
3.times { |index| print "tick " } # 0, 1, 2
puts Ruby has a
for keyword, but Rubyists almost never use it. The idiomatic counting loop is a method on a range or integer: (1..5).each, 5.downto(1), 3.times. The loop variable arrives as a block parameter and is scoped to the block. This reflects the deeper pattern — iteration in Ruby is a method call that yields to a block, not a built-in control structure.Iterating a collection
program ForEach;
var
fruits: array[0..2] of string;
fruit: string;
begin
fruits[0] := 'apple';
fruits[1] := 'banana';
fruits[2] := 'cherry';
for fruit in fruits do
writeln(fruit);
end. fruits = ["apple", "banana", "cherry"]
fruits.each { |fruit| puts fruit }
# each_with_index gives the position too:
fruits.each_with_index do |fruit, index|
puts "#{index}: #{fruit}"
end Modern Pascal's
for...in walks a collection, and Ruby's each is its direct counterpart — except each is a method that hands each element to a block. When you also need the index, each_with_index yields both, sparing you the manual counter. The block form ({ |fruit| ... } or do |fruit| ... end) is the heartbeat of Ruby iteration.while & until
program WhileLoop;
var
count: integer;
begin
count := 1;
while count <= 5 do
begin
write(count, ' ');
Inc(count);
end;
writeln;
count := 1;
repeat
write(count, ' ');
Inc(count);
until count > 5;
writeln;
end. count = 1
while count <= 5
print count, " "
count += 1
end
puts
count = 1
until count > 5 # until = while not
print count, " "
count += 1
end
puts Ruby's
while matches Pascal's, closing with end instead of begin/end. In place of Pascal's repeat...until, Ruby offers until, which loops while a condition is false — the negation of while. Ruby has no Inc; use the compound assignment count += 1.break, next & loop
program LoopControl;
var
index: integer;
begin
for index := 1 to 10 do
begin
if index = 8 then Break;
if index mod 2 = 0 then Continue;
write(index, ' ');
end;
writeln;
end. (1..10).each do |index|
break if index == 8 # leave the loop
next if index.even? # skip to the next iteration
print index, " "
end
puts # 1 3 5 7
# loop runs forever until break:
count = 0
loop do
count += 1
break if count > 3
end
puts count # 4 Ruby's
break matches Pascal's Break, and next plays the role of Pascal's Continue — skipping to the next iteration. Ruby adds loop do ... end, an unconditional infinite loop you exit with break, handy when the exit test is most natural in the middle of the body.Procedures & Functions
Procedures & functions become methods
program Methods;
procedure Greet(name: string);
begin
writeln('Hello, ', name, '!');
end;
function Square(n: integer): integer;
begin
Result := n * n;
end;
begin
Greet('Alice');
writeln(Square(5));
end. def greet(name)
puts "Hello, #{name}!"
end
def square(n)
n * n # last expression is the return value
end
greet("Alice")
puts square(5) Ruby has one keyword,
def, for what Pascal splits into procedure and function. There is no return-type declaration and no parameter types. Most strikingly, there is no Result variable and usually no return: a method implicitly returns the value of its last expression, so square just ends with n * n.Default & keyword arguments
program DefaultArgs;
function Greeting(name: string; salutation: string = 'Hello'): string;
begin
Result := salutation + ', ' + name + '!';
end;
begin
writeln(Greeting('Alice'));
writeln(Greeting('Bob', 'Hi'));
end. def greeting(name, salutation: "Hello")
"#{salutation}, #{name}!"
end
puts greeting("Alice") # Hello, Alice!
puts greeting("Bob", salutation: "Hi") # Hi, Bob!
# Default that is just positional:
def power(base, exponent = 2) = base ** exponent
puts power(5) # 25 Both languages support default parameter values. Ruby adds keyword arguments —
salutation: names the parameter at the call site, so argument order stops mattering and the call documents itself. The def power(base, exponent = 2) = ... form is Ruby's "endless method", a one-line definition mirroring Pascal's compact functions.Returning multiple values
program MultiReturn;
procedure DivMod(a, b: integer; var quotient, remainder: integer);
begin
quotient := a div b;
remainder := a mod b;
end;
var
q, r: integer;
begin
DivMod(17, 5, q, r);
writeln(q, ' remainder ', r);
end. def div_mod(a, b)
[a / b, a % b] # return an array
end
quotient, remainder = div_mod(17, 5) # destructure it
puts "#{quotient} remainder #{remainder}" Pascal returns extra values through
var parameters that the caller must declare in advance. Ruby returns an array and lets the caller destructure it in one assignment: quotient, remainder = div_mod(17, 5). Parallel assignment like this works anywhere, and it removes the need for pass-by-reference output parameters entirely.Variable arguments
program VarArgs;
function SumAll(const values: array of integer): integer;
var
value: integer;
begin
Result := 0;
for value in values do
Result := Result + value;
end;
begin
writeln(SumAll([1, 2, 3, 4, 5]));
end. def sum_all(*values) # * gathers extra args into an array
values.reduce(0) { |total, value| total + value }
end
puts sum_all(1, 2, 3, 4, 5) # 15
puts sum_all(10, 20) # 30
numbers = [1, 2, 3]
puts sum_all(*numbers) # * also splats an array into args Ruby's splat operator,
*, gathers any number of trailing arguments into an array inside the method (def sum_all(*values)) and, at a call site, expands an array back into separate arguments (sum_all(*numbers)). Pascal's array of open-array parameter is the closest analogue, but it requires the caller to wrap the values in an array literal.Blocks & Closures
Blocks — Ruby's defining feature
program Blocks;
type
TIntProc = procedure(n: integer);
procedure Repeat3(action: TIntProc);
var
index: integer;
begin
for index := 1 to 3 do
action(index);
end;
procedure ShowSquare(n: integer);
begin
writeln(n, ' squared is ', n * n);
end;
begin
Repeat3(@ShowSquare);
end. # A block is an anonymous chunk of code passed to a method.
# 'yield' runs whatever block the caller supplied:
def repeat3
(1..3).each { |index| yield index }
end
repeat3 { |n| puts "#{n} squared is #{n * n}" } The block is the feature with no real Pascal equivalent. In Pascal you declare a procedure type, define a named procedure, and pass
@ShowSquare as a function pointer. In Ruby you pass an inline, anonymous block right at the call, and the method runs it with yield. Almost every iteration method you have already seen — each, map, times — is built on this one mechanism.Brace vs do/end blocks
program BlockStyles;
const
numbers: array[1..3] of integer = (1, 2, 3);
var
index: integer;
begin
{ Pascal has no block syntax; this is a plain loop. }
for index := 1 to 3 do
begin
writeln(numbers[index] * 10);
end;
end. numbers = [1, 2, 3]
# Braces for a one-liner:
numbers.each { |number| puts number * 10 }
# do/end for multi-line bodies:
numbers.each do |number|
squared = number * number
puts "#{number} -> #{squared}"
end A block has two interchangeable forms: curly braces
{ |x| ... } for a single line, and do |x| ... end for multi-line bodies. The pipes around the parameters (|number|) are how a block declares the arguments it receives. By convention braces are for short, value-returning blocks and do/end for blocks run for their side effects — a stylistic distinction Pascal's begin/end never needs to make.Closures capture their scope
program Closures;
{ Free Pascal supports nested closures via "nested" functions
or anonymous methods, but they are an advanced feature and
do not capture variables as freely as Ruby blocks. }
var
base: integer;
function AddBase(n: integer): integer;
begin
Result := n + base; { captures the outer 'base' }
end;
begin
base := 100;
writeln(AddBase(5)); { 105 }
end. def make_adder(base)
->(n) { n + base } # a lambda that captures 'base'
end
add_ten = make_adder(10)
add_hundred = make_adder(100)
puts add_ten.call(5) # 15
puts add_hundred.call(5) # 105 A Ruby lambda (
->(n) { ... }) or proc is a block you store in a variable and call later, and it closes over the variables in scope when it was created — each make_adder call captures its own base. Call it with .call (or .()). Free Pascal's nested functions and anonymous methods can capture variables too, but the lightweight, store-and-pass-anywhere closure is far more central to everyday Ruby.Symbol-to-proc shorthand
program MapMethod;
uses SysUtils;
var
words: array[0..2] of string;
index: integer;
begin
words[0] := 'hello';
words[1] := 'world';
words[2] := 'ruby';
{ Apply a function to each element by hand. }
for index := 0 to 2 do
writeln(UpperCase(words[index]));
end. words = ["hello", "world", "ruby"]
# These two lines are equivalent:
puts words.map { |word| word.upcase }.inspect
puts words.map(&:upcase).inspect
# &:upcase turns the symbol :upcase into a block
# that calls .upcase on each element. When a block does nothing but call one method on each element, Ruby offers a terse shorthand:
&:upcase is equivalent to { |word| word.upcase }. The & converts the symbol :upcase into a block. You will see map(&:to_i), select(&:even?), and the like constantly — there is simply no Pascal equivalent, because Pascal has neither blocks nor symbols.Records & Classes
Records & classes
program ClassBasics;
type
TPerson = class
private
FName: string;
FAge: integer;
public
constructor Create(AName: string; AAge: integer);
procedure Greet;
end;
constructor TPerson.Create(AName: string; AAge: integer);
begin
FName := AName;
FAge := AAge;
end;
procedure TPerson.Greet;
begin
writeln('Hi, I am ', FName);
end;
var
person: TPerson;
begin
person := TPerson.Create('Alice', 30);
try
person.Greet;
finally
person.Free;
end;
end. class Person
def initialize(name, age) # the constructor
@name = name # @ marks an instance variable
@age = age
end
def greet
puts "Hi, I am #{@name}"
end
end
person = Person.new("Alice", 30)
person.greet
# No Free — the garbage collector reclaims it Ruby's class declaration puts the method bodies inside the class — there is no split between interface and implementation as in a Pascal unit. The constructor is always named
initialize and is invoked by Person.new. Instance variables are prefixed with @ and need no declaration; they appear when first assigned. And because Ruby is garbage-collected, there is no Free and no try...finally to balance it.Properties & accessors
program Properties;
type
TCounter = class
private
FValue: integer;
public
property Value: integer read FValue write FValue;
end;
var
counter: TCounter;
begin
counter := TCounter.Create;
try
counter.Value := 10;
writeln(counter.Value);
finally
counter.Free;
end;
end. class Counter
attr_accessor :value # generates reader AND writer
def initialize
@value = 0
end
end
counter = Counter.new
counter.value = 10 # calls the writer method
puts counter.value # calls the reader method Pascal's
property Value read FValue write FValue generates getter/setter access to a field. Ruby's attr_accessor :value does the same in one line, creating both a value reader and a value= writer. Use attr_reader for read-only or attr_writer for write-only. Under the hood counter.value = 10 is a real method call to value= — assignment syntax that dispatches to a method.Lightweight value objects
program ValueRecord;
type
TPoint = record
x, y: double;
end;
var
origin: TPoint;
begin
origin.x := 3.0;
origin.y := 4.0;
writeln('(', origin.x:0:1, ', ', origin.y:0:1, ')');
end. # Struct builds a small class with accessors in one line:
Point = Struct.new(:x, :y) do
def distance_from_origin
Math.sqrt(x ** 2 + y ** 2)
end
end
origin = Point.new(3.0, 4.0)
puts "(#{origin.x}, #{origin.y})"
puts origin.distance_from_origin # 5.0 For a simple bundle of named fields — Pascal's
record — Ruby offers Struct.new(:x, :y), which manufactures a class complete with a constructor and accessors. You can attach methods to it in the block, blurring the line Pascal draws between a passive record and an active class. (Ruby 3.2+ also has Data.define for immutable value objects.)self vs Self
program SelfRef;
type
TAccount = class
private
FBalance: integer;
public
function Deposit(amount: integer): TAccount;
end;
function TAccount.Deposit(amount: integer): TAccount;
begin
FBalance := FBalance + amount;
Result := Self; { return the instance for chaining }
end;
var
account: TAccount;
begin
account := TAccount.Create;
try
account.Deposit(100).Deposit(50);
writeln('Balance updated');
finally
account.Free;
end;
end. class Account
def initialize
@balance = 0
end
def deposit(amount)
@balance += amount
self # return the instance for chaining
end
def balance = @balance
end
account = Account.new
account.deposit(100).deposit(50)
puts account.balance # 150 Both languages use a self-reference for the current instance: Pascal's
Self and Ruby's lowercase self. Returning self from a method enables fluent chaining (account.deposit(100).deposit(50)). Inside a Ruby method you rarely write self to read an instance variable — @balance is already in scope — but you do return it explicitly when you want the method to be chainable.Inheritance & Modules
Inheritance & virtual methods
program Inheritance;
type
TAnimal = class
public
function Speak: string; virtual;
end;
TDog = class(TAnimal)
public
function Speak: string; override;
end;
function TAnimal.Speak: string;
begin
Result := '...';
end;
function TDog.Speak: string;
begin
Result := 'Woof!';
end;
var
animal: TAnimal;
begin
animal := TDog.Create;
try
writeln(animal.Speak); { Woof! }
finally
animal.Free;
end;
end. class Animal
def speak
"..."
end
end
class Dog < Animal # < means "inherits from"
def speak # overrides — no keyword needed
"Woof!"
end
end
animal = Dog.new
puts animal.speak # Woof! Ruby denotes inheritance with
< (class Dog < Animal) and supports only single inheritance, like Pascal. The big simplification: every method is "virtual" automatically. There is no virtual/override bookkeeping — defining a method with the same name in a subclass simply overrides it, and method lookup is always dynamic. Call the parent's version with the keyword super.Calling the parent — super
program SuperCall;
type
TBase = class
public
constructor Create; virtual;
end;
TDerived = class(TBase)
public
constructor Create; override;
end;
constructor TBase.Create;
begin
writeln('Base init');
end;
constructor TDerived.Create;
begin
inherited Create; { call the parent constructor }
writeln('Derived init');
end;
var
obj: TDerived;
begin
obj := TDerived.Create;
obj.Free;
end. class Base
def initialize
puts "Base init"
end
end
class Derived < Base
def initialize
super # call Base#initialize
puts "Derived init"
end
end
Derived.new Where Pascal writes
inherited Create to invoke the parent method, Ruby writes super. A bare super forwards the current method's arguments to the parent automatically; super(x, y) passes explicit ones, and super() passes none. It works in any method, not just the constructor.Modules & mixins vs interfaces
program Interfaces;
type
IGreetable = interface
function Greet: string;
end;
TRobot = class(TInterfacedObject, IGreetable)
public
function Greet: string;
end;
function TRobot.Greet: string;
begin
Result := 'BEEP BOOP';
end;
var
greetable: IGreetable;
begin
greetable := TRobot.Create;
writeln(greetable.Greet);
end. module Greetable # a mixin, not an interface
def greet
"Hi, I am #{name}" # uses a method the includer provides
end
end
class Robot
include Greetable # mix the module's methods in
def name = "R2D2"
end
puts Robot.new.greet # Hi, I am R2D2 A Pascal
interface declares method signatures a class must implement. A Ruby module goes further: it supplies actual method bodies that you mix into a class with include. This is composition by mixin, and it sidesteps single inheritance — a class can include any number of modules. Standard mixins like Comparable and Enumerable hand you dozens of methods in exchange for implementing just one or two.Comparable mixin
program Comparing;
type
TVersion = class
public
Major: integer;
function CompareTo(other: TVersion): integer;
end;
function TVersion.CompareTo(other: TVersion): integer;
begin
Result := Major - other.Major;
end;
var
a, b: TVersion;
begin
a := TVersion.Create; a.Major := 2;
b := TVersion.Create; b.Major := 5;
if a.CompareTo(b) < 0 then
writeln('a is older');
a.Free; b.Free;
end. class Version
include Comparable # gain <, >, ==, between?, clamp...
attr_reader :major
def initialize(major) = @major = major
def <=>(other) # define ONE method, the spaceship
major <=> other.major
end
end
puts Version.new(2) < Version.new(5) # true
puts [Version.new(5), Version.new(2)].min.major # 2 Implement the single
<=> ("spaceship") method — which returns -1, 0, or 1 like Pascal's CompareTo — then include Comparable, and Ruby gives your class <, <=, ==, >, >=, between?, clamp, and array min/max/sort for free. This is the payoff of mixins: a little protocol unlocks a large, consistent interface.Enumerations
Enumerated types
program Enums;
type
TColor = (Red, Green, Blue);
var
color: TColor;
begin
color := Green;
case color of
Red: writeln('Red');
Green: writeln('Green');
Blue: writeln('Blue');
end;
writeln(Ord(color)); { 1 }
end. # Ruby has no enum type; symbols are the idiom:
COLORS = [:red, :green, :blue]
color = :green
case color
when :red then puts "Red"
when :green then puts "Green"
when :blue then puts "Blue"
end
puts COLORS.index(color) # 1 — position stands in for Ord Ruby has no enumerated type. The idiomatic substitute is a set of symbols —
:red, :green, :blue — which are self-documenting, comparable, and usable as case labels. You lose the compiler's guarantee that a variable holds only a declared value, and there is no built-in Ord; if you need ordinal positions, store the symbols in an array and use index.Named integer constants
program EnumValues;
type
TPriority = (Low = 1, Medium = 5, High = 10);
var
priority: TPriority;
begin
priority := High;
writeln('Priority value: ', Ord(priority)); { 10 }
end. # Constants inside a module act as a namespaced enum:
module Priority
LOW = 1
MEDIUM = 5
HIGH = 10
end
priority = Priority::HIGH
puts "Priority value: #{priority}" # 10 When you need enum members with explicit integer values — Pascal's
(Low = 1, ...) — group plain constants inside a module, which provides a namespace. You reach them with :: (Priority::HIGH), the scope-resolution operator. This is just integers with names, so there is no type safety, but it reads clearly and keeps the names from polluting the global scope.Error Handling
Raising & rescuing
program Exceptions;
uses SysUtils;
begin
try
raise Exception.Create('something broke');
except
on E: Exception do
writeln('Caught: ', E.Message);
end;
end. begin
raise "something broke" # raises a RuntimeError
rescue => error
puts "Caught: #{error.message}"
end Ruby's
begin/rescue/end is the counterpart to Pascal's try/except/end. raise matches Pascal's raise; given a bare string it creates a RuntimeError with that message. The rescue => error clause binds the exception object, whose .message holds the text — directly analogous to on E: Exception do and E.Message.Rescuing specific types
program SpecificExceptions;
uses SysUtils;
var
value: integer;
begin
try
value := StrToInt('not a number');
writeln(value);
except
on E: EConvertError do
writeln('Bad number: ', E.Message);
on E: Exception do
writeln('Other error: ', E.Message);
end;
end. begin
value = Integer("not a number") # raises ArgumentError
puts value
rescue ArgumentError => error
puts "Bad number: #{error.message}"
rescue StandardError => error
puts "Other error: #{error.message}"
end Multiple
rescue clauses match by exception class, most specific first, exactly like Pascal's stacked on E: SomeType do handlers. A bare rescue with no class catches StandardError (the everyday base class) — not every possible error, which protects you from accidentally swallowing signals and exits. Ruby's exception hierarchy parallels Pascal's, with StandardError playing the role of Exception.ensure vs finally
program FinallyBlock;
uses Classes;
var
resource: TStringList;
begin
resource := TStringList.Create;
try
resource.Add('working');
writeln(resource[0]);
finally
resource.Free; { always runs }
writeln('Cleaned up');
end;
end. def process
puts "working"
raise "oops" if false
ensure
puts "Cleaned up" # always runs, error or not
end
begin
process
rescue => error
puts "Caught: #{error.message}"
end Ruby's
ensure is Pascal's finally: its body runs whether the protected code succeeds or raises. Because Ruby manages memory, ensure is needed less often than Pascal's finally — there is no Free to guarantee — but it remains essential for closing files, releasing locks, and other non-memory cleanup. Note ensure can attach directly to a method body, without an explicit begin.Custom exception classes
program CustomException;
uses SysUtils;
type
EValidationError = class(Exception);
begin
try
raise EValidationError.Create('age must be positive');
except
on E: EValidationError do
writeln('Validation failed: ', E.Message);
end;
end. class ValidationError < StandardError
end
begin
raise ValidationError, "age must be positive"
rescue ValidationError => error
puts "Validation failed: #{error.message}"
end A custom exception is just a class that inherits from
StandardError (Pascal subclasses Exception). The raise ValidationError, "message" form constructs the exception and sets its message in one step. Defining domain-specific exception classes — and rescuing them precisely — works the same in both languages; only the base class name differs.Metaprogramming & Duck Typing
Duck typing
program DuckTyping;
{ Pascal cannot do this: a parameter's type is fixed,
and only values of that type (or descendants) are accepted.
You would need a common base class or interface. }
type
TSpeaker = class
function Speak: string; virtual; abstract;
end;
begin
writeln('Pascal requires a shared type');
end. # No shared type needed — only that the object responds to .speak:
class Dog; def speak = "Woof"; end
class Cat; def speak = "Meow"; end
class Robot; def speak = "BEEP"; end
def announce(thing)
puts thing.speak # works for ANY object with #speak
end
[Dog.new, Cat.new, Robot.new].each { |thing| announce(thing) } This is the philosophical heart of the difference. Pascal binds a parameter to a type and accepts only that type or its descendants; sharing behaviour across unrelated classes requires a common base class or interface. Ruby asks no such question —
announce calls thing.speak and works for any object that responds to speak, related or not. "If it walks like a duck and quacks like a duck, it is a duck."Introspection
program Introspection;
{ Pascal's RTTI exists but is limited and verbose. There is
no easy runtime question like "does this respond to X?". }
type
TWidget = class
procedure Draw;
end;
procedure TWidget.Draw;
begin
writeln('drawing');
end;
begin
writeln('Pascal RTTI is limited');
end. value = "hello"
puts value.class # String
puts value.respond_to?(:upcase) # true
puts value.respond_to?(:push) # false
puts value.methods.size > 100 # true — strings have many methods
puts 42.is_a?(Numeric) # true
puts value.frozen? # true (literals are frozen) Ruby objects are fully introspectable at run time. You can ask any object for its
.class, whether it .respond_to? a method, whether it .is_a? some class, or for the entire list of .methods it understands. Pascal has RTTI, but it is comparatively limited and verbose; the casual, everywhere-available reflection Ruby offers is a different category of capability, and it is what makes duck typing safe to rely on.Open classes
program OpenClasses;
{ Pascal classes are closed: once compiled, you cannot add a
method to an existing class such as the string type. A class
helper can extend a type, but only within its own scope and
with restrictions. }
begin
writeln('Pascal classes are closed at compile time');
end. # Reopen the built-in Integer class and add a method:
class Integer
def factorial
(1..self).reduce(1, :*)
end
end
puts 5.factorial # 120
puts 0.factorial # 1 Ruby classes are open: you can reopen any class — even a built-in like
Integer or String — and add or replace methods at run time. Suddenly every integer in the program has a factorial method. Pascal classes are sealed once compiled (class helpers offer a constrained, scoped imitation). This power demands restraint — carelessly patching core classes is the much-warned-about "monkey patching" — but it underlies much of Ruby's expressiveness, Rails included.Dynamic methods
program DynamicMethods;
{ Pascal resolves every method call at compile time. There is
no hook for "a method that does not exist was called", and no
way to synthesise methods at run time. }
begin
writeln('Pascal has no method_missing equivalent');
end. class FlexibleConfig
def initialize
@settings = {}
end
def method_missing(name, *args)
text = name.to_s
if text.end_with?("=")
@settings[text.chomp("=").to_sym] = args.first
else
@settings[name]
end
end
end
config = FlexibleConfig.new
config.host = "localhost" # no 'host=' method defined!
puts config.host # localhost When you call a method an object does not define, Ruby invokes
method_missing with the method name and arguments — a hook that lets an object respond to messages it was never explicitly given, here turning arbitrary config.anything = x into hash storage. Pascal resolves every call at compile time and has nothing comparable. This run-time method dispatch is how Rails conjures methods like find_by_email that no one ever wrote.I/O & Files
Reading input
program ReadInput;
var
name: string;
begin
Write('Enter your name: ');
ReadLn(name);
writeln('Hello, ', name, '!');
end. print "Enter your name: "
name = gets.chomp # gets reads a line incl. newline
puts "Hello, #{name}!" # chomp strips the trailing newline Ruby's
gets reads one line from standard input — but unlike Pascal's ReadLn it keeps the trailing newline, so the idiom is gets.chomp to strip it. print writes without a newline (use it for prompts); puts adds one. This example cannot run in the browser, since there is no console to type into.Writing a file
program WriteFile;
var
output: TextFile;
begin
AssignFile(output, 'greeting.txt');
Rewrite(output);
try
writeln(output, 'Hello from Pascal');
writeln(output, 'Second line');
finally
CloseFile(output);
end;
end. # The block form opens and auto-closes the file:
File.open("greeting.txt", "w") do |file|
file.puts "Hello from Ruby"
file.puts "Second line"
end
# File is closed automatically when the block ends.
puts "File written" Pascal's file workflow is a four-step ritual:
AssignFile, Rewrite, write, CloseFile — with a finally to guarantee the close. Ruby collapses this into File.open(name, "w") do |file| ... end: the block receives the open file and Ruby closes it automatically when the block exits, even on an exception. This block-with-cleanup pattern is everywhere in Ruby. (File I/O is unavailable in the browser sandbox.)Reading a file
program ReadFile;
var
input: TextFile;
line: string;
begin
AssignFile(input, 'data.txt');
Reset(input);
try
while not Eof(input) do
begin
ReadLn(input, line);
writeln(line);
end;
finally
CloseFile(input);
end;
end. # Slurp the whole file:
contents = File.read("data.txt")
puts contents
# Or iterate lines without loading it all at once:
File.foreach("data.txt") do |line|
puts line.chomp
end
# Read into an array of lines:
lines = File.readlines("data.txt")
puts lines.length Reading collapses just as dramatically.
File.read returns the entire file as one string; File.foreach streams it line by line for large files; File.readlines returns an array of lines. None require the explicit Reset/Eof/ReadLn/CloseFile loop Pascal needs — and each closes the file for you. (This example is marked non-runnable because the browser has no filesystem.)