Ada is a strong statically typed imperative, [object-oriented](https://ada-lang.io/docs/arm/AA-3/AA-3.9), [real-time](https://ada-lang.io/docs/arm/AA-D), [parallel](https://ada-lang.io/docs/arm/AA-9) and [distributed](https://ada-lang.io/docs/arm/AA-9) programming language from the Pascal/Algol family of languages, but nowadays, it only has a passing resemblance to Pascal, with the only remnants left being the ```begin/end``` keyword pair, the ```:=``` assignment symbol, records and ```if/case``` control statement structures.
Ada was originally designed to be an [object-based](https://ada-lang.io/docs/arm/AA-3/AA-3.3) language and to replace 100's of languages in use by the US government. This means that all entities are objects, not in the object-oriented sense. The language became [Object-Oriented](https://ada-lang.io/docs/arm/AA-3/AA-3.9) in 1995, and added [interfaces](https://ada-lang.io/docs/arm/AA-3/AA-3.9#Subclause_3.9.4) derived from Java in 2005. [Contract based](https://ada-lang.io/docs/arm/AA-13/AA-13.1#Subclause_13.1.1) programming was introduced with Ada 2012.
Ada was designed to be easy to read and learn, even for non-programmers, e.g. management within an organisation, therefore programs written in the language tend to be a bit more verbose.
Ada is a modern programming language, and now has a package manager like other modern languages, Alire, see below.
```ada
-- Comments are written with a double hyphen and exist until the end of
-- the line.
-- You do not need to call the entry point "Main" or "main," you should
-- name it based on what the program does.
procedure Empty is
-- This is a declarative part.
begin
-- Statements go here.
null; -- Do nothing here.
end Empty;
-- Ada compilers accept compilation units which can be library packages,
-- tasks, sub-programs, generics, etc.
-- This is where "context clauses" go, these can be pragmas or "with"
-- statements. "with" is equivalent to "include" or "import" in other
-- languages.
with Ada.Text_IO; -- Get access to a library package.
procedure Hello is
begin
Ada.Text_IO.Put_Line ("Hello, world");
Ada.Text_IO.Put ("Hello again, world");
Ada.Text_IO.New_Line;
end Hello;
-- Ada has a real module system. Modules are called packages and are split into
-- two component parts, the specification and a body.
-- It is important to introduce packages early, as you will be using them from
-- the start.
package Stuff is
-- We could add the following line in order to tell the compiler that this
-- package does not have to run any code before the "main" procedure starts.
-- pragma Preelaborate;
-- Packages can be nested within the same file or externally.
-- Nested packages are accessed via dot notation, e.g. Stuff.Things.My.
package Things is
My : constant Integer := 100;
end Things;
-- If there are sub-programs declared within the specification, the body
-- of the sub-program must be declared within the package body.
procedure Do_Something; -- If a subprogram takes no parameters, empty
-- parentheses are not required, unlike other
-- languages.
-- We can also make generic sub-programs.
generic
type Element is (<>); -- The "(<>)" notation specifies that only
-- discrete types can be passed into the generic.
procedure Swap (Left, Right : in out Element);
-- Sometimes we want to hide how a type is defined from the outside world
-- so that nobody can mess with it directly. The full type must be defined
-- within the private section below.
type Blobs is private;
-- We can also make types "limited" by putting this keyword after the "is"
-- keyword, this means that the user cannot copy objects of that type
-- around, like they normally could.
private
type Blobs is new Integer range -25 .. 25;
end Stuff;
package body Stuff is
-- Sub-program body.
procedure Do_Something is
-- We can nest sub-programs too.
-- Parameters are defined with the direction of travel, in, in out, out.
-- If the direction of travel is not specified, they are in by default.
function Times_4 (Value : in Integer) return Integer is
begin
return Value * 4;
end Times_4;
I : Integer := 4;
begin
I := Times_4 (I);
end Do_Something;
-- Generic procedure body.
procedure Swap (Left, Right : in out Element) is
Temp : Element := Left;
begin
Left := Right;
Right := Temp;
end Swap;
begin
-- If we need to initialise something within the package, we can do it
-- here.
Do_Something;
end Stuff;
with Ada.Unchecked_Conversion;
with Ada.Text_IO;
with Stuff;
procedure LearnAdaInY is
-- Indentation is 3 spaces.
-- The most important feature in Ada is the type. Objects have types and an
-- object of one type cannot be assigned to an object of another type.
-- You can, and should, define your own types for the domain you are
-- modelling. But you can use the standard types to start with and then
-- replace them later with your own types, this could be called a form of
-- gradual typing.
-- The standard types would only really be a good starting point for binding
-- to other languages, like C. Ada is the only language with a standardised
-- way to bind with C, Fortran and COBOL! See the links in the References
-- section with more information on binding to these languages.
type Degrees is range 0 .. 360; -- This is a type. Its underlying
-- representation is an Integer.
type Hues is (Red, Green, Blue, Purple, Yellow); -- So is this. Here, we
-- are declaring an
-- Enumeration.
-- This is a modular type. They behave like Integers that automatically
-- wrap around. In this specific case, the range would be 0 .. 359.
-- If we added 1 to a variable containing the value 359, we would receive
-- back 0. They are very useful for arrays.
type Degrees_Wrap is mod 360;
-- You can restrict a type's range using a subtype, this makes them
-- compatible with each other, i.e. the subtype can be assigned to an
-- object of the type, as can be seen below.
subtype Primaries is Hues range Red .. Blue; -- This is a range.
-- You can define variables or constants like this:
-- Var_Name : Type := Value;
-- 10 is a universal integer. These universal numerics can be used with
-- This next line implements a repeat ... until or do ... while loop construct.
-- Comment it out for an infinite loop.
exit Infinite when Counter = 5; -- Equality tests use a single "=".
end loop Infinite; -- Useful when implementing state machines.
end;
declare -- We don't have to have a label.
Counter : Positive := Positive'First; -- This is 1.
begin
while Counter <10
loop
IO.Put_Line ("Counter = " & Counter'Image);
Counter := Counter + 1; -- There is no explicit inc/decrement.
-- Ada 2022 introduced @ for LHS, so the above would be written as
-- Counter := @ + 1; -- Try it, -gnat2022.
end loop;
end;
declare
package Hue_IO is new IO.Enumeration_IO (Hues);
-- We can have multiple packages on one line, but I tend to use one
-- package per line for readability.
use IO, Hue_IO;
begin
Put ("Hues : "); -- Note, no prefix.
-- Because we are using the 'Range attribute, the compiler knows it is
-- safe and can omit run-time checks here.
for Hue in Hues'Range
loop
Put (Hue);
-- Types and objects know about their bounds, their First .. Last
-- values. These can be specified as range types.
if Hue /= Hues'Last then -- The /= means "not equal to" like the
-- maths symbol ≠.
Put (", ");
end if;
end loop;
IO.New_Line;
end;
-- All objects know their bounds, including strings.
declare
C : Character := Str (50); -- Warning caused and exception raised at
-- runtime.
-- The exception raised above can only be handled by an outer scope,
-- see wikibook link below.
begin
null; -- We will never get to this point because of the above.
end;
exception
when Constraint_Error =>
IO.Put_Line ("Caught the exception");
end LearnAdaInY;
```
Now, that's a lot of information for a basic intro to Ada, and I've only touched the surface, there's much more to look at in the references section below. I haven't even touched on dynamic memory allocation which includes [pools](https://ada-lang.io/docs/arm/AA-13/AA-13.11), this is because for the most part, Ada programs don't need it, you can do a lot without it.
As I stated above, Ada barely looks like Pascal and if you look at the original [Green specification](https://apps.dtic.mil/sti/trecms/pdf/ADB950587.pdf) (Warning: Huge 4575 page scanned PDF - starting on page 460), it looks nothing like it at all (page 505 of that PDF).
The above source code will compile, but also will give warnings showing the power of the strong static type system.
## Download this source
If you already have the GNAT toolchain installed, you can cut and paste the above into a new file, e.g. ```learn-ada-in-y.ada``` and then run the following:
```bash
$ gnatchop learn-ada-in-y.ada # This breaks the program into its specification ".ads" and body ".adb".
$ gnatmake empty.adb # gnatmake takes care of compilation of all units and linking.
$ gnatmake hello.adb
$ gnatmake learnadainy.adb
```
Or, download [Alire](https://alire.ada.dev), copy it to somewhere in your PATH and then do the following:
**N.B.** Alire will automatically install the toolchain for you if you don't have one installed and will ask you to select which you want to use.
Multi-line comments are not allowed as they are error prone.
> Such comments would require a closing comment delimiter and this would again raise the dangers associated with the (unintentional) omission of the closing delimiter: entire sections of a program could be ignored by the compiler without the programmer realizing it