Hello World & Structure
Hello, World
program Hello;
begin
writeln('Hello, World!');
end.with Ada.Text_IO; use Ada.Text_IO;
procedure Example is
begin
Put_Line("Hello, World!");
end Example;Ada packages replace Pascal's implicit I/O. The main unit is a
procedure, not a program. GNAT, the usual Ada compiler, expects each file to be named after the unit it holds, and warns that the file name does not match the unit name when they differ. Every Ada example here lives in a file named example.adb, so the procedure is Example.Compiling
{ fpc hello.pas }
{ ./hello }-- gnatmake example.adb
-- ./examplegnatmake compiles and links in one step. Individual phases use gcc -c, gnatbind, and gnatlink.Printing integers and floats
program PrintDemo;
begin
writeln(42);
writeln(3.14:8:2);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
with Ada.Float_Text_IO;
procedure Example is
begin
Ada.Integer_Text_IO.Put(42, Width => 0); New_Line;
Ada.Float_Text_IO.Put(3.14, Fore => 1, Aft => 2, Exp => 0); New_Line;
end Example;Put_Line accepts only strings. Numbers are printed with Ada.Integer_Text_IO.Put and Ada.Float_Text_IO.Put, or turned into a string first with 'Image. Their Put procedures share one name, but the types of the arguments tell them apart, so use-ing all three packages causes no ambiguity; writing them fully qualified, as here, is a choice of style.Importing packages
{ Pascal: uses makes all names directly visible }
program Demo;
uses SysUtils;
begin
writeln(IntToStr(42));
writeln(UpperCase('hello'));
end.-- with only: all names are qualified
-- with Ada.Text_IO;
-- Ada.Text_IO.Put_Line("qualified");
-- with + use: names visible directly (like Pascal uses)
with Ada.Text_IO; use Ada.Text_IO;
procedure Example is
begin
Put_Line("unqualified, from use Ada.Text_IO");
Ada.Text_IO.Put_Line("qualified still works too");
end Example;with makes a package visible (you can qualify its names). use additionally brings names into direct scope — equivalent to Pascal's uses. You may with without use to keep namespaces explicit.Variables & Types
Variable declarations
program Demo;
var
count : Integer;
ratio : Real;
flag : Boolean;
begin
count := 10;
ratio := 3.14;
flag := True;
writeln(count, ' ', ratio:4:2, ' ', flag);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
with Ada.Float_Text_IO;
procedure Example is
Count : Integer := 10;
Ratio : Float := 3.14;
Flag : Boolean := True;
begin
Ada.Integer_Text_IO.Put(Count, Width => 0); New_Line;
Ada.Float_Text_IO.Put(Ratio, Fore => 1, Aft => 2, Exp => 0); New_Line;
Put_Line(Boolean'Image(Flag));
end Example;Ada declarations live between
is and begin. Variables may carry an initializer (:= value) inline. Writing Ada.Integer_Text_IO.Put fully qualified is a choice of style: with use clauses, the argument types alone pick the right Put.Integer types
program Demo;
var
small : ShortInt; { -128..127 }
medium : Integer; { 32-bit }
big : Int64; { 64-bit }
pos : Word; { 0..65535 }
begin
medium := 1000000;
writeln(medium);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
Small : Short_Integer := 0;
Medium : Integer := 1_000_000;
Big : Long_Long_Integer := 0;
Natural_N : Natural := 0; -- >= 0
Positive_N : Positive := 1; -- >= 1
begin
Ada.Integer_Text_IO.Put(Medium, Width => 0); New_Line;
end Example;Ada provides
Natural (≥ 0) and Positive (≥ 1) as predefined subtypes of Integer. Assigning a negative value to Natural raises Constraint_Error at runtime.Boolean & logical operators
program Demo;
var
ready, done: Boolean;
begin
ready := True;
done := False;
if ready and not done then
writeln('Go!')
else
writeln('Wait');
end.with Ada.Text_IO; use Ada.Text_IO;
procedure Example is
Ready : Boolean := True;
Done : Boolean := False;
begin
if Ready and then not Done then
Put_Line("Go!");
else
Put_Line("Wait");
end if;
end Example;Ada keeps Pascal's
and/or/not keywords but adds and then and or else for short-circuit evaluation. and then is idiomatic Ada; bare and always evaluates both sides.Constants
program Demo;
const
MaxSize = 100;
Pi = 3.14159;
Greeting = 'Hello';
begin
writeln(MaxSize);
writeln(Greeting);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
Max_Size : constant Integer := 100;
Pi : constant := 3.14159;
Greeting : constant String := "Hello";
begin
Ada.Integer_Text_IO.Put(Max_Size, Width => 0); New_Line;
Put_Line(Greeting);
end Example;Ada constants use
constant as a modifier on the type annotation. A constant without a type (constant := 3.14159) is a universal numeric constant that adapts to context — like a Pascal untyped constant.Named type declarations
program Demo;
type
Color = (Red, Green, Blue);
Score = 0..100;
var
hue : Color;
grade: Score;
begin
hue := Green;
grade := 87;
writeln(Ord(hue));
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
type Color is (Red, Green, Blue);
type Score is new Integer range 0..100;
Hue : Color := Green;
Grade : Score := 87;
begin
Ada.Integer_Text_IO.Put(Color'Pos(Hue), Width => 0); New_Line;
Ada.Integer_Text_IO.Put(Integer(Grade), Width => 0); New_Line;
end Example;type Score is new Integer range 0..100 creates a derived type — a distinct type that cannot be mixed with plain Integer without an explicit conversion. Pascal's type Score = 0..100 creates a subrange that still interoperates freely with Integer.Strings
Fixed-length strings
program Demo;
var
name: String[10];
begin
name := 'Alice';
writeln(name, ' len=', Length(name));
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
Name : String(1..10) := "Alice ";
begin
Put_Line(Name);
Ada.Integer_Text_IO.Put(Name'Length, Width => 0); New_Line;
end Example;Ada's
String type is a fixed-length array of Character. A String variable's bounds are fixed when it is declared — assigning a ten-character string to a String(1..5) raises Constraint_Error. Use Unbounded_String when the length varies at runtime.Variable-length strings
program Demo;
var
name: AnsiString;
begin
name := 'Alice';
name := name + '!';
writeln(name, ' len=', Length(name));
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
procedure Example is
Name : Unbounded_String := To_Unbounded_String("Alice");
begin
Append(Name, "!");
Put_Line(To_String(Name));
Ada.Integer_Text_IO.Put(Length(Name), Width => 0); New_Line;
end Example;Unbounded_String from Ada.Strings.Unbounded is the variable-length string type, analogous to Pascal's AnsiString. To_String converts back to a fixed String when needed.String concatenation
program Demo;
var
first, last, full: AnsiString;
begin
first := 'Ada';
last := 'Lovelace';
full := first + ' ' + last;
writeln(full);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
procedure Example is
First : Unbounded_String := To_Unbounded_String("Ada");
Last : Unbounded_String := To_Unbounded_String("Lovelace");
Full : Unbounded_String;
begin
Full := First & " " & Last;
Put_Line(To_String(Full));
end Example;Ada uses
& for string concatenation instead of Pascal's +. With Unbounded_String, concatenation extends the string dynamically. With fixed String, the result's length is fixed when the variable holding it is declared — which can be at run time: Label : constant String := "Count:" & Integer'Image (Count); takes whatever length the concatenation produces.String attributes & slices
program Demo;
var
word: AnsiString;
sub : AnsiString;
begin
word := 'Hello';
sub := Copy(word, 2, 3); { 'ell' }
writeln(sub, ' len=', Length(word));
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
Word : constant String := "Hello";
Sub : constant String := Word(2..4); -- "ell"
begin
Put_Line(Sub);
Ada.Integer_Text_IO.Put(Word'Length, Width => 0); New_Line;
end Example;Ada strings support array slicing with
(Low..High) notation. Attributes like 'Length, 'First, and 'Last replace Pascal's Length() function and manual indexing.Subtypes & Constraints
Subrange types
program Demo;
type
MonthRange = 1..12; { type and var names must differ: }
ScoreRange = 0..100; { Pascal is case-insensitive! }
var
month: MonthRange;
grade: ScoreRange;
begin
month := 6;
grade := 87;
writeln(month, ' ', grade);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
subtype Month_Type is Integer range 1..12;
subtype Score_Type is Integer range 0..100;
Month : Month_Type := 6;
Grade : Score_Type := 87;
begin
Ada.Integer_Text_IO.Put(Month, Width => 0); New_Line;
Ada.Integer_Text_IO.Put(Grade, Width => 0); New_Line;
end Example;Ada's
subtype plays the role of Pascal's subrange type. Assigning a value outside the range raises Constraint_Error at runtime. When the compiler can see the violation, GNAT also warns at compile time — but still builds the program, which then raises.Derived types (distinct units)
program Demo;
{ Pascal: type aliases still interoperate freely }
type
Meters = Real;
Seconds = Real;
var
distance: Meters;
time : Seconds;
begin
distance := 100.0;
time := distance; { no error -- same base type }
writeln(time:4:1);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO;
procedure Example is
type Meters is new Float;
type Seconds is new Float;
Distance : Meters := 100.0;
-- Time : Seconds := Distance; -- compile error: incompatible types
Same : Meters := Distance;
begin
Ada.Float_Text_IO.Put(Float(Same), Fore => 1, Aft => 1, Exp => 0);
New_Line;
end Example;Ada's
type T is new Base creates a genuinely distinct type. Meters and Seconds cannot be mixed arithmetically — accidental unit errors become compile errors. Pascal's type declarations create aliases that still freely interoperate.Constraint_Error at runtime
program Demo;
uses SysUtils;
type Month = 1..12;
var m: Month;
begin
try
m := 13;
except
on E: ERangeError do
writeln('Range error: ', E.Message);
end;
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
subtype Month_Type is Integer range 1..12;
Month : Month_Type := 6;
begin
begin
Month := 13;
exception
when Constraint_Error =>
Put_Line("Constraint_Error: value out of range");
end;
Ada.Integer_Text_IO.Put(Month, Width => 0); New_Line;
end Example;Ada raises
Constraint_Error for any range or type constraint violation. Exception handlers use exception when E => at the end of any begin...end block — no separate try keyword needed.Control Flow
If / elsif
program Demo;
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.with Ada.Text_IO; use Ada.Text_IO;
procedure Example is
Score : Integer := 75;
begin
if Score >= 90 then
Put_Line("A");
elsif Score >= 80 then
Put_Line("B");
elsif Score >= 70 then
Put_Line("C");
else
Put_Line("F");
end if;
end Example;Ada uses
elsif (not else if or elseif) and closes the whole chain with end if;. No begin/end pair is needed inside branches.Case statement
program Demo;
var month: Integer;
begin
month := 6;
case month of
12, 1, 2 : writeln('Winter');
3..5 : writeln('Spring');
6..8 : writeln('Summer');
9..11 : writeln('Autumn');
end;
end.with Ada.Text_IO; use Ada.Text_IO;
procedure Example is
Month : Integer := 6;
begin
case Month is
when 12 | 1 | 2 => Put_Line("Winter");
when 3..5 => Put_Line("Spring");
when 6..8 => Put_Line("Summer");
when 9..11 => Put_Line("Autumn");
when others => Put_Line("Invalid");
end case;
end Example;Ada uses
when clauses with | for multiple values, closes with end case;, and requires when others => if not all values are covered. Pascal uses commas and colons instead.Short-circuit operators
{ and then / or else require {$mode delphi} in FPC;
use and / or in {$mode objfpc} }
program Demo;
var
numbers: array[1..5] of Integer;
index : Integer;
begin
numbers[1] := 42;
index := 1;
if (index >= 1) and (index <= 5) and
(numbers[index] > 0) then
writeln('Valid positive: ', numbers[index]);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
Numbers : array(1..5) of Integer := (42, 0, 0, 0, 0);
Index : Integer := 1;
begin
if Index >= 1 and then Index <= 5 and then
Numbers(Index) > 0 then
Ada.Integer_Text_IO.Put(Numbers(Index), Width => 0); New_Line;
end if;
end Example;Ada's
and then and or else are short-circuit operators — the right side is not evaluated if the left side determines the result. Bare and/or always evaluate both sides. Ada also uses parentheses () for array indexing instead of [].Loops
For loop
program Demo;
var i: Integer;
begin
for i := 1 to 5 do
write(i, ' ');
writeln;
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
begin
for Index in 1..5 loop
Ada.Integer_Text_IO.Put(Index, Width => 0);
Put(" ");
end loop;
New_Line;
end Example;Ada uses
in instead of :=/to, and closes with end loop;. The loop variable is declared implicitly, is read-only inside the loop, and does not exist after the loop ends.Counting down
program Demo;
var i: Integer;
begin
for i := 5 downto 1 do
write(i, ' ');
writeln;
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
begin
for Index in reverse 1..5 loop
Ada.Integer_Text_IO.Put(Index, Width => 0);
Put(" ");
end loop;
New_Line;
end Example;Ada uses
in reverse to count down; downto does not exist. The range is still written low..high — the reverse keyword drives iteration backwards.While loop
program Demo;
var count: Integer;
begin
count := 1;
while count <= 5 do
begin
write(count, ' ');
Inc(count);
end;
writeln;
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
Count : Integer := 1;
begin
while Count <= 5 loop
Ada.Integer_Text_IO.Put(Count, Width => 0);
Put(" ");
Count := Count + 1;
end loop;
New_Line;
end Example;Ada replaces Pascal's
begin/end pair inside while with loop...end loop;. There is no Inc builtin — increment is written as Count := Count + 1.Repeat-until / loop-exit
program Demo;
var count: Integer;
begin
count := 1;
repeat
write(count, ' ');
Inc(count);
until count > 5;
writeln;
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
Count : Integer := 1;
begin
loop
Ada.Integer_Text_IO.Put(Count, Width => 0);
Put(" ");
Count := Count + 1;
exit when Count > 5;
end loop;
New_Line;
end Example;Ada has no
repeat...until. The idiom is loop ... exit when Cond; end loop;. The exit when can appear anywhere in the body, not just at the end.Iterating over an array
program Demo;
var
numbers: array[1..5] of Integer;
i: Integer;
begin
numbers[1] := 10; numbers[2] := 20;
numbers[3] := 30; numbers[4] := 40;
numbers[5] := 50;
for i := 1 to 5 do
write(numbers[i], ' ');
writeln;
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
Numbers : array(1..5) of Integer := (10, 20, 30, 40, 50);
begin
for Index in Numbers'Range loop
Ada.Integer_Text_IO.Put(Numbers(Index), Width => 0);
Put(" ");
end loop;
New_Line;
end Example;Ada arrays use parentheses for indexing —
Numbers(Index) not Numbers[Index]. The 'Range attribute yields the array's declared bounds, so the loop automatically covers all elements.Procedures & Functions
Procedures
program Demo;
procedure Greet(name: String);
begin
writeln('Hello, ', name, '!');
end;
begin
Greet('Alice');
end.with Ada.Text_IO; use Ada.Text_IO;
procedure Example is
procedure Greet(Name : String) is
begin
Put_Line("Hello, " & Name & "!");
end Greet;
begin
Greet("Alice");
end Example;Ada procedures are declared in the declarative region between
is and begin. The body starts with is (not a semicolon) and the end conventionally repeats the procedure name (optional, but checked when written). Parameters default to in mode (read-only).Functions
program Demo;
function Square(n: Integer): Integer;
begin
result := n * n;
end;
begin
writeln(Square(7));
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
function Square(N : Integer) return Integer is
begin
return N * N;
end Square;
begin
Ada.Integer_Text_IO.Put(Square(7), Width => 0); New_Line;
end Example;Ada uses
return in both the signature (return Integer) and the body (return N * N). Pascal's result := (or FunctionName :=) becomes an explicit return statement.In / out parameters
program Demo;
procedure Swap(var a, b: Integer);
var temp: Integer;
begin
temp := a;
a := b;
b := temp;
end;
var x, y: Integer;
begin
x := 5; y := 10;
Swap(x, y);
writeln(x, ' ', y);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
procedure Swap(A : in out Integer; B : in out Integer) is
Temp : Integer := A;
begin
A := B;
B := Temp;
end Swap;
X : Integer := 5;
Y : Integer := 10;
begin
Swap(X, Y);
Ada.Integer_Text_IO.Put(X, Width => 0); Put(" ");
Ada.Integer_Text_IO.Put(Y, Width => 0); New_Line;
end Example;Pascal's
var parameter becomes Ada's in out mode. Ada also distinguishes in (read-only, the default) and out (for results — reading one before assigning it compiles, but draws a warning that it may be referenced before it has a value).Nested subprograms
program Demo;
procedure Outer;
procedure Inner(n: Integer);
begin
writeln('Inner: ', n);
end;
begin
Inner(42);
end;
begin
Outer;
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
procedure Outer is
procedure Inner(N : Integer) is
begin
Put("Inner: ");
Ada.Integer_Text_IO.Put(N, Width => 0); New_Line;
end Inner;
begin
Inner(42);
end Outer;
begin
Outer;
end Example;Ada fully supports nested subprograms just as Pascal does. Inner subprograms can access outer variables and may themselves contain further nested declarations.
Records
Record types
program Demo;
type
Point = record
x, y: Integer;
end;
var origin: Point;
begin
origin.x := 0;
origin.y := 0;
writeln(origin.x, ' ', origin.y);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
type Point is record
X, Y : Integer;
end record;
Origin : Point;
begin
Origin.X := 0;
Origin.Y := 0;
Ada.Integer_Text_IO.Put(Origin.X, Width => 0); Put(" ");
Ada.Integer_Text_IO.Put(Origin.Y, Width => 0); New_Line;
end Example;Ada's
record...end record is nearly identical to Pascal's record...end. Field access uses the same dot notation. Ada convention capitalizes field names (X, Y).Record aggregates
program Demo;
type
Point = record x, y: Integer; end;
var
p1, p2: Point;
begin
p1.x := 3; p1.y := 4; { field-by-field init }
p2.x := 0; p2.y := 0;
writeln(p1.x, ' ', p1.y);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
type Point is record X, Y : Integer; end record;
P1 : Point := (X => 3, Y => 4); -- named aggregate
P2 : Point := (0, 0); -- positional aggregate
begin
Ada.Integer_Text_IO.Put(P1.X, Width => 0); Put(" ");
Ada.Integer_Text_IO.Put(P1.Y, Width => 0); New_Line;
Ada.Integer_Text_IO.Put(P2.X, Width => 0); Put(" ");
Ada.Integer_Text_IO.Put(P2.Y, Width => 0); New_Line;
end Example;Ada record aggregates use named associations (
Field => Value) or positional order. Named form is preferred — it is self-documenting and immune to field reordering.Procedures operating on records
program Demo;
type
Person = record
name: String[20];
age : Integer;
end;
procedure PrintPerson(p: Person);
begin
writeln(p.name, ' age ', p.age);
end;
var alice: Person;
begin
alice.name := 'Alice';
alice.age := 30;
PrintPerson(alice);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
type Person is record
Name : String(1..5);
Age : Integer;
end record;
procedure Print_Person(P : Person) is
begin
Put_Line(P.Name & " age" & Integer'Image(P.Age));
end Print_Person;
Alice : Person := (Name => "Alice", Age => 30);
begin
Print_Person(Alice);
end Example;An Ada
in parameter (the default) is read-only — the compiler chooses whether to copy the record or pass a reference to it, and assigning to its fields does not compile. Use in out to allow modification, where Pascal uses var. The Integer'Image attribute converts an integer to its string representation.Packages
Package structure
{ Pascal unit: one file }
unit Geometry;
interface
type Point = record x, y: Real; end;
function Distance(a, b: Point): Real;
implementation
uses Math;
function Distance(a, b: Point): Real;
begin
result := Sqrt((b.x-a.x)*(b.x-a.x) + (b.y-a.y)*(b.y-a.y));
end;
end.-- geometry.ads (spec)
package Geometry is
type Point is record X, Y : Float; end record;
function Distance(A, B : Point) return Float;
end Geometry;
-- geometry.adb (body)
with Ada.Numerics.Elementary_Functions;
package body Geometry is
function Distance(A, B : Point) return Float is
DX : Float := B.X - A.X;
DY : Float := B.Y - A.Y;
begin
return Ada.Numerics.Elementary_Functions.Sqrt(DX*DX + DY*DY);
end Distance;
end Geometry;Ada splits a package into a spec file (
.ads — the public interface) and a body file (.adb — the implementation); a package whose spec declares nothing that needs a body, such as one holding only constants, has no body at all. The spec is visible to callers; the body is private. This is a stricter version of Pascal's interface/implementation split.Qualified vs unqualified names
{ Pascal: uses makes all names directly visible }
{ uses SysUtils; }
{ writeln(IntToStr(42)); -- unqualified }-- with only: all names are qualified
with Ada.Text_IO;
procedure Example is
begin
Ada.Text_IO.Put_Line("qualified");
end Example;
-- with + use: names visible directly
-- with Ada.Text_IO; use Ada.Text_IO;
-- procedure Example is
-- begin
-- Put_Line("unqualified");
-- end Example;with makes a package visible (you can qualify its names). use additionally brings names into direct scope — equivalent to Pascal's uses. You may with without use to keep namespaces explicit.Access Types
Access types (pointers)
program Demo;
var
ptr: ^Integer;
begin
New(ptr);
ptr^ := 42;
writeln(ptr^);
Dispose(ptr);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
type Int_Access is access Integer;
Ptr : Int_Access := new Integer'(42);
begin
Ada.Integer_Text_IO.Put(Ptr.all, Width => 0); New_Line;
Ptr.all := 55;
Ada.Integer_Text_IO.Put(Ptr.all, Width => 0); New_Line;
end Example;Ada uses
access T instead of Pascal's ^T, and .all to dereference instead of ^. new Integer'(42) allocates and initializes in one step. There is no Dispose here: without garbage collection, the allocation simply lives until the program ends, and freeing it early goes through the deliberately loud Ada.Unchecked_Deallocation.Access to records
program Demo;
type
PersonPtr = ^Person;
Person = record
name: String[5];
age : Integer;
end;
var ptr: PersonPtr;
begin
New(ptr);
ptr^.name := 'Bob';
ptr^.age := 25;
writeln(ptr^.name, ' ', ptr^.age);
Dispose(ptr);
end.with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Example is
type Person is record
Name : String(1..3);
Age : Integer;
end record;
type Person_Access is access Person;
Ptr : Person_Access := new Person;
begin
Ptr.Name := "Bob";
Ptr.Age := 25;
Put_Line(Ptr.Name);
Ada.Integer_Text_IO.Put(Ptr.Age, Width => 0); New_Line;
end Example;Ada automatically dereferences access values for record field access —
Ptr.Name is shorthand for Ptr.all.Name. No ^. or -> needed. The compiler inserts the dereference transparently.Exception Handling
Exception handling
program Demo;
uses SysUtils;
var n, d: Integer;
begin
d := 0;
try
n := 10 div d;
except
on E: EDivByZero do
writeln('Division by zero: ', E.Message);
on E: Exception do
writeln('Error: ', E.Message);
end;
end.with Ada.Text_IO; use Ada.Text_IO;
procedure Example is
N : Integer;
D : Integer := 0;
begin
begin
N := 10 / D;
exception
when Constraint_Error =>
Put_Line("Numeric error (div by zero)");
when others =>
Put_Line("Unexpected error");
end;
end Example;Ada exception handlers live at the end of any
begin...end block, introduced by the exception keyword — no separate try. Multiple when clauses name specific exceptions; when others is the catch-all.Raising exceptions
program Demo;
uses SysUtils;
procedure CheckAge(age: Integer);
begin
if age < 0 then
raise Exception.Create('Negative age: ' + IntToStr(age));
end;
begin
try
CheckAge(-1);
except
on E: Exception do writeln(E.Message);
end;
end.with Ada.Text_IO; use Ada.Text_IO;
procedure Example is
procedure Check_Age(Age : Integer) is
begin
if Age < 0 then
raise Constraint_Error with "Negative age: " & Integer'Image(Age);
end if;
end Check_Age;
begin
begin
Check_Age(-1);
exception
when Constraint_Error =>
Put_Line("Caught: negative age");
end;
end Example;Ada's
raise ExceptionName with "message" attaches a detail string without needing an exception object. The optional with clause provides the message that appears in Exception_Message(E).Custom exceptions
program Demo;
uses SysUtils;
type
EValueError = class(Exception);
procedure Validate(n: Integer);
begin
if n > 100 then
raise EValueError.Create('Too large: ' + IntToStr(n));
end;
begin
try
Validate(200);
except
on E: EValueError do writeln('Value error: ', E.Message);
end;
end.with Ada.Text_IO; use Ada.Text_IO;
procedure Example is
Value_Error : exception;
procedure Validate(N : Integer) is
begin
if N > 100 then
raise Value_Error with "Too large: " & Integer'Image(N);
end if;
end Validate;
begin
begin
Validate(200);
exception
when Value_Error =>
Put_Line("Value error: value out of range");
end;
end Example;Declaring a custom exception in Ada is a single line — no class definition needed. An exception in Ada is not an object of any type:
Value_Error : exception; declares a name that raise and when can refer to, and using it as a value does not compile. Pascal (FPC) uses class declarations (class(Exception)) for the same purpose.