Ada. Time-tested, safe and secure.
Ada. Time-tested, safe and secure.

"Hello, world!" programs

edit

"Hello, world!"

edit

A common example of a language's syntax is the Hello world program. Here is a straightforward Ada Implementation:

File: hello_world_1.adb, Crate: basic (view, plain text, download with Alire, Alire crate info)
with Ada.Text_IO;

procedure Hello is
begin
   Ada.Text_IO.Put_Line("Hello, world!");
end Hello;

The with statement adds the package Ada.Text_IO to the program. This package comes with every Ada compiler and contains all functionality needed for textual Input/Output. The with statement makes the declarations of Ada.Text_IO available to procedure Hello. This includes the types declared in Ada.Text_IO, the subprograms of Ada.Text_IO and everything else that is declared in Ada.Text_IO for public use. In Ada, packages can be used as toolboxes. Text_IO provides a collection of tools for textual input and output in one easy-to-access module. Here is a partial glimpse at package Ada.Text_IO:

package Ada.Text_IO is

   type File_Type is limited private;

   --  more stuff

   procedure Open(File : in out File_Type;
                  Mode : File_Mode;
                  Name : String;
                  Form : String := "");

   --  more stuff

   procedure Put_Line (Item : String);

   --  more stuff

end Ada.Text_IO;

Next in the program we declare a main procedure. An Ada main procedure does not need to be called "main". Any simple name is fine so here it is Hello. Compilers might allow procedures or functions to be used as main subprograms. [1]

The call on Ada.Text_IO.Put_Line writes the text "Hello World" to the current output file.

A with clause makes the content of a package visible by selection: we need to prefix the procedure name Put_Line from the Text_IO package with its full package name Ada.Text_IO. If you need procedures from a package more often some form of shortcut is needed. There are two options open:

"Hello, world!" with renames

edit

By renaming a package it is possible to give a shorter alias to any package name.[2] This reduces the typing involved while still keeping some of the readability.

File: hello_world_2.adb, Crate: basic (view, plain text, download with Alire, Alire crate info)
with Ada.Text_IO;

procedure Hello is
   package IO renames Ada.Text_IO;
begin
   IO.Put_Line("Hello, world!");
   IO.New_Line;
   IO.Put_Line("I am an Ada program with package rename.");
end Hello;

"Hello, world!" with local use

edit

The use clause makes all the content of a package directly visible for the scope it is declared it. use can be placed locally or globally (see below). Like rename this reduces the typing involved while still keeping some of the readability.

File: hello_world_3.adb, Crate: basic (view, plain text, download with Alire, Alire crate info)
with Ada.Text_IO;

procedure Hello is
   use Ada.Text_IO;   
begin
   Put_Line("Hello, world!");
   New_Line;
   Put_Line("I am an Ada program with package use.");
end Hello;

use can be used for packages and in the form of use type for types. use type makes only the operators of the given type directly visible but not any other operations on the type.

"Hello, world!" with global use

edit

Using use clause outside any scope will makes all the content of a package directly visible for the whole compilation unit. It allows even less typing but removes more of the readability and can lead to name clashes.

File: hello_world_4.adb, Crate: basic (view, plain text, download with Alire, Alire crate info)
with Ada.Text_IO;
use Ada.Text_IO;

procedure Hello is    
begin
   Put_Line("Hello, world!");
   New_Line;
   Put_Line("I am an Ada program with package use.");
end Hello;

With that many options one need to consider which option to use when. One suggested "rule of thumb":

  • global use for the most used package(s)
  • renames for most other package(s)
  • local use for packages only used in a single procedure
  • no use use or renames for package(s) only used once

You might have another simpler rule (for example, always use package Ada and its children, never use anything else).

Another rule from the early days of Ada development was global use for all packages unless a name clash occurs.

Compiling the "Hello, world!" program

edit

For information on how to build the "Hello, world!" program on various compilers, see the Building chapter.

FAQ: Why is "Hello, world!" so big?

edit

Ada beginners frequently ask how it can be that such a simple program as "Hello, world!" results in such a large executable. The reason has nothing to do with Ada but can usually be found in the compiler and linker options used — or better, not used.

Standard behavior for Ada compilers — or good compilers in general — is not to create the best code possible but to be optimized for ease of use. This is done to ensure a system that works "out of the box" and thus does not frighten away potential new users with unneeded complexity.

The GNAT project files, which you can download alongside the example programs, use better tuned compiler, binder and linker options. If you use those your "Hello, world!" will be a lot smaller:

 32K ./Linux-i686-Debug/hello_world_1
8.0K ./Linux-i686-Release/hello_world_1
 36K ./Linux-x86_64-Debug/hello_world_1
 12K ./Linux-x86_64-Release/hello_world_1
1.1M ./Windows_NT-i686-Debug/hello_world_1.exe
 16K ./Windows_NT-i686-Release/hello_world_1.exe
 32K ./VMS-AXP-Debug/hello_world_1.exe
 12K ./VMS-AXP-Release/hello_world_1.exe

For comparison the sizes for a plain gnat make compile:

497K hello_world_1 (Linux i686)
500K hello_world_1 (Linux x86_64)
1.5M hello_world_1.exe (Windows_NT i686)
589K hello_world_1.exe (VMS AXP)

Worth mentioning is that hello_world (Ada, C, C++) compiled with GNAT/MSVC 7.1/GCC(C) all produces executables with approximately the same size given comparable optimisation and linker methods.

Things to look out for

edit

It will help to be prepared to spot a number of significant features of Ada that are important for learning its syntax and semantics.

Comb Format

edit

There is a comb format in all the control structures and module structures. See the following examples for the comb format. You don't have to understand what the examples do yet - just look for the similarities in layout.

if Boolean expression then
   statements
elsif Boolean expression then
   statements
else
   statements
end if;
while Boolean expression loop
   statements
end loop;
for variable in range loop
   statements
end loop;
declare
   declarations
begin
   statements
exception
   handlers
end;
procedure P (parameters : in out type) is
   declarations
begin
   statements
exception
   handlers
end P;
function F (parameters : in type) return type is
   declarations
begin
   statements
exception
   handlers
end F;
package P is
   declarations
private
   declarations
end P;
generic
   declarations
package P is
   declarations
private
   declarations
end P;
generic
   declarations
procedure P (parameters : in out type);

Note that semicolons consistently terminate statements and declarations; the empty line (or a semicolon alone) is not a valid statement: the null statement is

null;

Type and subtype

edit

There is an important distinction between type and subtype: a type is given by a set of values and their operations. A subtype is given by a type, and a constraint that limits the set of values. Values are always of a type. Objects (constants and variables) are of a subtype. This generalizes, clarifies and systematizes a relationship, e.g. between Integer and 1..100, that is handled ad hoc in the semantics of Pascal.

Constrained types and unconstrained types

edit

There is an important distinction between constrained types and unconstrained types. An unconstrained type has one or more free parameters that affect its size or shape. A constrained type fixes the values of these parameters and so determines its size and shape. Loosely speaking, objects must be of a constrained type, but formal parameters may be of an unconstrained type (they adopt the constraint of any corresponding actual parameter). This solves the problem of array parameters in Pascal (among other things).

Dynamic types

edit

Where values in Pascal or C must be static (e.g. the subscript bounds of an array) they may be dynamic in Ada. However, static expressions are required in certain cases where dynamic evaluation would not permit a reasonable implementation (e.g. in setting the number of digits of precision of a floating point type).

Separation of concerns

edit

Ada consistently supports a separation of interface and mechanism. You can see this in the format of a package, which separates its declaration from its body; and in the concept of a private type, whose representation in terms of Ada data structures is inaccessible outside the scope containing its definition.

Where to ask for help

edit

Most Ada experts lurk on the Usenet newsgroups comp.lang.ada (English) and fr.comp.lang.ada (French); they are accessible either with a newsreader or through one of the many web interfaces. This is the place for all questions related to Ada.

People on these newsgroups are willing to help but will not do students' homework for them; they will not post complete answers to assignments. Instead, they will provide guidance for students to find their own answers.

For more online resources, see the External links section in this wikibook's introduction.

Notes

edit
  1. Main subprograms may even have parameters; it is implementation-defined what kinds of subprograms can be used as main subprograms. The reference manual explains the details in 10.2: LRM 10.2(29) [Annotated]: “…, an implementation is required to support all main subprograms that are public parameterless library procedures.” Library means not nested in another subprogram, for example, and other things that needn't concern us now.
  2. renames can also be used for procedures, functions, variables, array elements. It can not be used for types — a type rename can be accomplished with subtype.