Hello world in Ada

My favorite language is F#, but Ada is also interesting.

mkdir src
Put in this source directory the ada "main" file , hello.adb :
Code:
with Text_IO; 
use Text_IO;
procedure hello is
begin
   Put_Line("Hello world!");
end hello;

Create a gpr file , syntax is not always obvious, hello_world.gpr :
Code:
project Hello_World is
   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Exec_Dir use "bin";
   for Main use ("hello.adb");
   package Compiler is
       for Switches ("Ada") use ("-gnat2022", "-O2","-B","-d","-g");
   end Compiler;
   package Builder is
       for Executable ("hello.adb") use "hello.exe";
   end Builder;
end Hello_World;

Execute the following script , compile_run :
Code:
export CC=clang20
export CXX=clang20++
export GCC=clang20
rm -vfR ./obj/*
rm -vfR ./bin/*
gnatmake -vl -we -P hello_world.gpr
./bin/hello.exe
 
How to do object orientation in ada :

In src directory put , counter_pkg.ads :
Code:
-- counter_pkg.ads
package Counter_Pkg is
   type Counter is private;
   function Counter_Make (X: Integer) return Counter;
   procedure Increment(C : in out Counter);
   function Get_Value(C : Counter) return Integer;

private

   type Counter is record
      Value : Integer := 0;
   end record;

end Counter_Pkg;

counter_pkg.adb :
Code:
-- counter_pkg.adb
package body Counter_Pkg is

   function Counter_Make (X: Integer) return Counter is
   c : Counter;
   begin
       c.Value:=X;
       return c;
   end Counter_Make;

   procedure Increment(C : in out Counter) is
   begin
      C.Value := C.Value + 1;
   end Increment;

   function Get_Value(C : Counter) return Integer is
   begin
      return C.Value;
   end Get_Value;

end Counter_Pkg;

hello.adb :
Code:
with Text_IO;
use  Text_IO;
with Counter_Pkg;
use  Counter_Pkg;

procedure hello is

   c : Counter := Counter_Make(5);
   i : Integer := 0;

begin
   Put_Line("Hello world!");
   c.Increment;
   c.Increment;
   i:=c.Get_Value;
   Put_Line("The value is: " & Integer'Image(i));
end hello;

Change the .gpr file and add "gnatX" flag,
Code:
package Compiler is
       for Switches ("Ada") use ("-gnat2022", "-O2","-B","-d","-g","-gnatX");
   end Compiler;
 
Sidenote, some interesting compiler switches to put in the .gpr file,
Code:
package Compiler is
       for Switches ("Ada") use ("-gnat2022", "-O2","-B","-d","-gnatX","-Og","-ffunction-sections","-fdata-sections","-g","-gnatwa","-gnatw.X","-gnatVa","-gnatW8");
end Compiler;
 
And now something different, "manual" memory management in ada.
Ok, memory is safe as opposed to C & C++,

Code:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Unchecked_Deallocation;

procedure Heap_Example is

   type Integer_Ptr is access Integer;
   Ptr : Integer_Ptr;
   procedure Free is new Ada.Unchecked_Deallocation(Integer, Integer_Ptr);

begin

   Ptr := new Integer'(42);
   Put_Line("Value on heap:" & Integer'Image(Ptr.all));
   Free(Ptr);

end Heap_Example;
 
I quite like Ada and have a few legacy projects at work that use(d) it. We decided to migrate them to C++/sys rather than SPARK.

Ada is one of the few languages that supports RAII. Binding Ada to system libraries can leverage that but it isn't common knowledge so memory safety issues typically creep in here (almost exclusively). It would make a cracking interview question.

gnatmake never sat well with me. For one, it ties you down to a single vendor of Ada (Greenhills, DDC, PTC are common vendors outside of AdaCore/GNAT). But just like rustc, the compiler itself has a naive approach to incremental builds so standard Makefiles are complex to write.
 
Some data-types, record, array, vector, double-linked-list,

Code:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors;
with Ada.Containers.Doubly_Linked_Lists;

procedure Example is

type Person is record
   Name : String (1 .. 10);
   Age  : Integer;
end record;
John : Person := (Name => "John Smith", Age => 30);

type My_Index is range 1 .. 5;
type My_Int_Array is array (My_Index) of Integer;
Arr : My_Int_Array := [10, 20, 30, 40, 50];

package Integer_Vectors is new Ada.Containers.Vectors
    (Index_Type   => Natural,Element_Type => Integer); use Integer_Vectors;
My_Vector : Vector;

package Integer_Lists is new Ada.Containers.Doubly_Linked_Lists (Integer); use Integer_Lists;
My_List : List;

Pos : Integer_lists.Cursor;

begin

    John.Age := John.Age + 1;
    Put_Line("John has age : " & John.Age'Image);

    for I in Arr'Range loop
        Put_Line("Element at index" & I'Image & " is" & Arr(I)'Image);
    end loop;

    My_Vector.Append(10);
    My_Vector.Append(20);
    My_Vector.Append(30);
    Put_Line("First element: " & My_Vector.Element(0)'Image);
    Put_Line("Vector length: " & My_Vector.Length'Image);
    for Item of My_Vector loop
        Put_Line("Value: " & Item'Image);
    end loop;

    My_List.Append (10);
    My_List.Append (20);
    My_List.Prepend (5);
    Put_Line ("Forward Traversal:");
    for Cursor in My_List.Iterate loop
        Put_Line (Integer'Image (Element (Cursor)));
    end loop;
   
    Put_Line ("Backward Traversal:");
    Pos := My_list.Last;
    while Has_Element (Pos) loop
        Put_Line (Integer'Image (Element (Pos)));
        Pos := Previous (Pos);
    end loop;

end Example;
 
Back
Top