Магия Ада

Речь, конечно, о магии языка Ада.

Возможно, это восторг неофита, но тем не менее. Недели две назад я решил погрузиться в язык Ada. Он вполне вписывается в мои предпочтения: компилируемый, строго (точнее, очень строго) типизированный, со сборщиком мусора. По таким критериям сегодня выбор достаточно широк, я хорошо отношусь к C# и Go.

Ada позволяет объявить модульный тип, то есть тип с ограниченной длиной. Потом на основании такого типа можно создавать массивы, которые «закольцованы», то есть в таких массивах невозможно выйти за его границу.

Нам нужно, например, подсчитать длины сторон треугольника.

Объявление

Мы объявляем тип Indextype длиной 3, а также объявляем структуру точки и функцию расстояния между двумя точками.

geometry.ads (Источник)

WITH Ada.Text_Io;

PACKAGE Geometry IS
   TYPE Indextype IS MOD 3;
   PACKAGE Index_Io IS NEW Ada.Text_Io.Modular_Io (Num => Indextype);

   TYPE Point IS RECORD
      X, Y  : FLOAT   := 0.0;
      Index : INTEGER := 0;
   END RECORD;
   FUNCTION Get_Distance (M, N : POINT) RETURN FLOAT;
   PROCEDURE Put (P : POINT);
END Geometry;

Детали реализации

В самой тестовой программе создаём переменную Index модульного типа, объявленного в пакете Geometry. Объявляем тип «треугольник»: массив точек длиной, равной размерности типа Indextype (по-моему, это очень здорово).

Для начала заполняем массив точек случайными координатами и выводим их на экран.

geometry.adb (Источник)

WITH Ada.Numerics.Elementary_Functions;
WITH Ada.Float_Text_Io;
WITH Ada.Integer_Text_Io;
WITH Ada.Text_Io;
USE Ada.Numerics.Elementary_Functions;

PACKAGE BODY Geometry IS

   FUNCTION Get_Distance (M, N : POINT) RETURN FLOAT IS
   BEGIN
      RETURN Sqrt (FLOAT ((N.X - M.X)**2) + FLOAT ((N.Y - M.Y)**2));
   END Get_Distance;

   PROCEDURE Put (P : POINT) IS
   BEGIN
      Ada.Text_Io.Put ("Point");
      Ada.Integer_Text_Io.Put (P.Index);
      Ada.Text_Io.Put (": ");
      Ada.Text_Io.Put ("p.X is");
      Ada.Float_Text_Io.Put (P.X, Aft => 4, Exp => 0);
      Ada.Text_Io.Put (", p.Y is");
      Ada.Float_Text_Io.Put (P.Y, Aft => 4, Exp => 0);
      Ada.Text_Io.New_Line;
   END Put;

END Geometry;

Тестовая программа

И в самом конце самое интересное: мы можем пройтись итератором по всему диапазону (размерности) типа Indextype, и для каждого случая подсчитать расстояние между текущей и следующей точкой, а также любой другой, используя ±N; в языке типа C++ мы не cможем, находясь на последней позиции массива, взять значение из позиции «текущая + 1». Здесь же — легко и просто.

getline.adb (Источник)

-- This program fills an array with three points with random coordinates
-- and then calculates the distances between them.

WITH Ada.Float_Text_Io;
WITH Ada.Integer_Text_Io;
WITH Ada.Text_Io;
WITH Ada.Numerics.Float_Random;
WITH Geometry;
USE Geometry;

PROCEDURE Getline IS

   Index : Geometry.INDEXTYPE := 0;
   Seed  : Ada.Numerics.Float_Random.GENERATOR;

   TYPE Triangle IS ARRAY (Geometry.INDEXTYPE'Range) OF Geometry.POINT;
   Tri : TRIANGLE;

BEGIN
   Ada.Numerics.Float_Random.Reset (Seed);

   FOR I IN Geometry.INDEXTYPE'Range LOOP
      Tri (I) :=
        (X     => Ada.Numerics.Float_Random.Random (Seed) * 10.0,
         Y     => Ada.Numerics.Float_Random.Random (Seed) * 10.0,
         Index => INTEGER (I));
   END LOOP;

   FOR I IN Geometry.INDEXTYPE'Range LOOP
      Geometry.Put (Tri (I));
      Geometry.Put (Tri (I + 1));
      Ada.Text_Io.Put ("Distance between points");
      Ada.Integer_Text_Io.Put (Tri (I).Index, Width => 2);
      Ada.Text_Io.Put (" and ");
      Ada.Integer_Text_Io.Put (Tri (I + 1).Index, Width => 2);
      Ada.Text_Io.Put (" is ");
      Ada.Float_Text_Io.Put
        (Geometry.Get_Distance (Tri (I + 1), Tri (I)), Aft => 4, Exp => 0);
      Ada.Text_Io.New_Line (2);
   END LOOP;
END Getline;

Делаем gnatmake getline && getline, вывод программы будет приблизительно таким:

Point          0: p.X is 4.5906, p.Y is 9.9080
Point          1: p.X is 3.4309, p.Y is 8.8065
Distance between points 0 and  1 is  1.5994

Point          1: p.X is 3.4309, p.Y is 8.8065
Point          2: p.X is 9.1367, p.Y is 9.4752
Distance between points 1 and  2 is  5.7448

Point          2: p.X is 9.1367, p.Y is 9.4752
Point          0: p.X is 4.5906, p.Y is 9.9080
Distance between points 2 and  0 is  4.5667