Что нового в Аде 202х

wiki:/graphics/ada_202x.jpg

Стандарт языка Ада 2012 был опубликован, как официальный документ ISO/IEC 8652:2012, в декабре 2012 года. В феврале 2016 был опубликован стандарт с техническими правками ISO/IEC 8652:2012/Cor 1:2016. Этот последний документ и определяет действующий стандарт языка Ада.

С момента публикации началась работа над следующей версией языка. Будущий стандарт условно называется Ada 202x. Окончательное название и дата публикации пока не известны.

Черновик стандарта можно посмотреть на сайте ada-auth.org. А подробную информацию о ходе разработки новой версии можно почерпнуть на странице Ada Rapporteur Group. Там же можно найти подробности по каждому отдельному рассмотренному вопросу AI12-XXXX-X.

Что же будет в новом стандарте Ады? Вот, с моей точки зрения, наиболее интересные нововведения.

Больше параллельности!

Много новых возможностей связаны с упрощением распараллеливанием программ.

Параллельные циклы и блоки

AI12-0119-1 AI12-0251-1

Вводится новое ключевое слово parallel. Оно используется в написании двух новых операторов.

Параллельный блок:

procedure Traverse (T : Expr_Ptr) is
begin
  if T /= null
    and then
     T.all in Binary_Operation'Class -- see 3.9.1
  then -- recurse down the binary tree
    parallel do
      Traverse (T.Left);
    and
      Traverse (T.Right);
    and
      Ada.Text_IO.Put_Line
        ("Processing " & Ada.Tags.Expanded_Name (T'Tag));
    end do;
  end if;
end Traverse;

Параллельный цикл:

parallel for I in Grid'Range(1) loop
   Grid(I, 1) := (for all J in Grid'Range(2) => Grid(I,J) = True);
end loop;

Для параллельного цикла можно задать количество параллельно исполняемых отрезков указав его как выражение либо как спецификацию индекса:

parallel (Num_CPUs) for I in Arr'Range loop
   A(I) := B(I) + C(I);
end loop;

declare
   Partial_Sum : array (1 .. Num_CPUs) of Integer := (others => 0);
begin
   parallel (Chunk in Partial_Sum'Range) for I in Arr'Range loop
      --  Какие-то сложные манипуляции
      Partial_Sum (Chunk) := @ + some_complicated_computation;
   end loop;

   Sum := Partial_Sum'Reduce ("+", 0);
end;

Поддержка Map-Reduce

AI12-0262-1 AI12-0242-1

Техника программирования Map-Reduce широко распространена. (Подробнее.) В место того, чтобы писать подпрограммы и циклы, необходим другой механизм при котором входные и промежуточные значения существуют в виде потока значений. Это позволит задействовать все параллельные устройства машины. Вводится новый атрибут Reduce:

V'Reduce(Reducer, Initial_Value[, Combiner]) 

Где в качестве V может выступать одно из

  • массив
  • контейнер
  • специальная конструкция value_sequence, синтаксис которой сходен с агрегатом контейнеров
value_sequence ::=
  '[' [parallel[(chunk_specification)]] iterated_component_association ']'

В итоге программа переберет все элементы V и начальное значение Initial_Value выполнит над ними подпрограмму Reducer, которая может быть функцией или процедурой:

function Reducer
  (Accumulator : Accum_Type;
   Value      : Value_Type) return Accum_Type;

procedure Reducer
  (Accumulator : in out Accum_Type;
   Value       : in Value_Type);

Вот пример вычисления факториала таким образом:

function Factorial(N : Natural) return Natural is
  ([for J in 1 .. N => J]'Reduce("*", 1));

Аспект Nonblocking

AI12-0064-2

Чтобы компилятор мог использовать параллельность по полной нужно гарантировать некоторые свойства программы. К ним относится наличие блокировок по ходу исполнения кода.

На этапе описания подпрограммы можно указать, что она не содержит блокирующих операций. Работает и на уровне пакетов:

package Ada.Calendar with Nonblocking is
  type Time is private;

Описание побочных эффектов

AI12-0079-1

Другим важным свойством связанным с распаралелливанием является отсутствие побочных эффектов исполнения кода. Для их описания вводится новый аспект Global. Синтаксис его не так прост. Можно

  • указывать „всё“ или «ничего»
  • перечислить глобальные переменные, которые подпрограмма читает и/или пишет
  • указать что используются переменные из заданного пакета или его приватной части
  • ссылочный тип
  • указать режим доступа (in, out, in out)
procedure X
  with Global => (in null,   --  нет побочных эффектов
                  out all);  --  любые побочные эффекты

procedure Y
  with Global => (in private of My_Package,
                  out access Integer);

Атомарные операции

AI12-0234-1 AI12-0321-1

Для упрощения реализации неблокирующих алгоритмов добавили

  • настраиваемый пакет System.Atomic_Operations.Exchange
    • функцию Atomic_Exchange
    • функцию Atomic_Compare_And_Exchange
  • пакет System.Atomic_Operations.Test_And_Set
    • функцию Atomic_Test_And_Set
    • функцию Atomic_Clear
  • функции проверки наличия функциональности Is_Lock_Free в обоих пакетах

Пример использования:

declare
   type Atomic_Boolean is new Boolean with Atomic;

   package Exchange is new 
     Atomic_Operations.Exchange (Atomic_Type => Atomic_Boolean);

   Lock : aliased Atomic_Boolean := False;

begin
  --  Obtain the lock
  while Exchange.Atomic_Exchange (Item => Lock, Value => True) loop
     null;
  end loop

  ... -- do stuff

  Lock := False; -- Release the lock
end;

Изменения в итераторах

В эту группу попадают несколько изменений.

Фильтры для итераторов

AI12-0250-1

Во всех конструкциях, где используются итераторы, теперь можно добавлять фильтр — условия при срабатывании которого элементы участвуют в итерации, а остальные пропускаются.

for J in 1 .. 10 when J mod 2 = 0 loop
   Ada.Text_IO.Put_Line (J'Img);
end loop;

Процедурные итераторы

AI12-0189-1

Вводится новый способ итерации по контейнеру. Контейнер определяет процедуру итерации принимающую на вход указатель на подпрограмму. Эта подпрограмма затем вызывается для нужных элементов контейнера. Чтобы упростить использование, вводится новый вид циклов. Тело такого цикла компилятор преобразует в анонимную подпрограмму и передаёт ссылку на неё в итератор.

   package Maps is
     ...
     procedure Iterate
      (Container : in Map;
       Process   : not null access procedure
                     (Key : in Key_Type; Element : in Element_Type));

   end Maps

   My_Map : Maps.Map;

   for (Key, Value) of My_Map.Iterate loop
      Put_Line (Key_Type'Image (Key) & " => " &
         Element_Type'Image (Value));
   end loop;

Параллельные циклы для контейнеров

AI12-0266-1

Для контейнерных типов также возможны параллельные циклы. Чтобы они работали для вашего собственного контейнера нужно предоставить итератор специального вида:

type Parallel_Iterator is limited interface and Forward_Iterator;

subtype Chunk_Index is Positive;

function Is_Split (Object : Parallel_Iterator)
   return Boolean is abstract;

procedure Split_Into_Chunks
  (Object     : in out Parallel_Iterator;
   Max_Chunks : Chunk_Index) is abstract;

function Chunk_Count
  (Object : Parallel_Iterator) return Chunk_Index
    is abstract;

function First
  (Object : Parallel_Iterator;
   Chunk  : Chunk_Index) return Cursor is abstract;

function Next
  (Object   : Parallel_Iterator;
   Position : Cursor;
   Chunk    : Chunk_Index) return Cursor is abstract;

Больше выразительности и удобства

Авторы языка стараются сделать его более выразительным и удобным. Сюда относится литералы для пользовательских типов, агрегаты для контейнеров, новые виды агрегатов для массивов и записей.

Числовые и строковые литералы для пользовательских типов

AI12-0249-1 AI12-0295-1

Новый аспект позволяет пользователю указать функцию преобразования числового литерала в данный тип. Это позволяет избежать явного вызова этой функции, например:

type Big_Integer is private
  with Integer_Literal => Big_Integer_Value;

function Big_Integer_Value (S : String)
  return Big_Integer;

...

Y : Big_Integer := -3;
--  Что эквивалентно записи:
--    Y : Big_Integer := - Big_Integer_Value ("3");

Аналогично аспект Real_Literal используется для дробных литералов, а String_Literal для строковых.

Итеративные ассоциации в агрегатах массивов

AI12-0061-1

Теперь можно будет писать так

 G : constant Matrix :=
    (for I in 1 .. 4 =>
       (for J in 1 .. 4 =>
          (if I = J then 1.0 else 0.0)));

Агрегаты контейнеров

AI12-0212-1

Появилась возможность инициализировать контейнеры с помощью агрегатов специального вида. Поддерживаются почти все стандартные контейнеры (кроме Multiway_Trees) и определенные пользователем контейнеры, для которых указаны специальные аспекты. Для записи агрегата используются квадратные скобки:

X : My_Set := [1, 2, 3];

Что равнозначно:

X : My_Set := Empty_Set;
Include (X, 1);
Include (X, 2);
Include (X, 3);

Соответственно, если вы определяете собственный контейнер, вы можете указать какими операциями его инициализировать:

type Set_Type is private
  with Aggregate => (Empty       => Empty_Set,
                     Add_Unnamed => Include);

function Empty_Set return Set_Type;

procedure Include (S : in out Set_Type; N : Element);

Для контейнеров типа ключ‐значение используется агрегат с именованным сопоставлением:

M := [12 => "house", 14 => "beige"];

Внутри контейнеров можно использовать итераторы. Есть также сокращенная форма, когда не нужно отдельно записывать значение ключа, например:

M := [for Key of Keys use Key => Integer'Image (Key)];
--  сокращенная форма:
M := [for Key of Keys => Integer'Image (Key)];

Агрегат с квадратными скобками можно использовать и для массивов. Им проще записывать массивы без элементов и с одним элементом, т.к. нет необходимости указывать индекс:

Keys : constant array (Positive range <>) of Integer := [2, 3, 5, 7];
K1   : constant array (Positive range <>) of Integer := [2];
K0   : constant array (Positive range <>) of Integer := [];
--  Для Ады 2012:
K1   : constant array (Positive range <>) of Integer := (1 => 2);
K0   : constant array (Positive range <>) of Integer := (1 .. 0 => <>);

Дельта агрегат

AI12-0127-1

Новая форма агрегата для замены части компонент новыми значениями. Удобно использовать с постусловиями:

  procedure The_Answer (V : in out Vector; A, B : in Integer)
     with Post => V = (V'Old with delta A .. B => 42.0, V'First => 0.0);

Атрибут Image для всех типов

AI12-0020-1

Теперь атрибуты Image, Wide_Image и Wide_Wide_Image работают для всех типов. Пользователь может определить результат этих атрибутов для своих сложных типов определив аспект Put_Image предоставив процедуру преобразования.

type T is record ...  end record
  with Put_Image => T_Image;
procedure T_Image
  (Arg    : T;
   Stream : not null access Ada.Streams.Root_Stream_Type'Class);

Плюха @

AI12-0125-3

Вводится сокращение в операторах присваивания для обозначение левой части.

Board (1, 1) := @ + 1;  -- An abbreviation for
Board (1, 1) := Board (1, 1) + 1;

Упрощённое переименование объектов

AI12-0275-1

При переименовании объекта можно опустить тип, так как он известен и так.

declare
   X renames Get_My_Position.X;
begin
   X := X + 1;
end;

Выражения‐определения

AI12-0236-1

Для удобства записи контрактов вводится новый вид выражений

declare_expression ::=
  declare {declare_item}
  begin body_expression

Например,

with Dynamic_Predicate =>
  (declare Q : constant Integer := H(S.A, S.B);
           R : constant Integer := G(S.C, S.D);
   begin
     (if W(Q, R) then F(Q) else Z(R)))

Контракты для параметров настраиваемых модулей

AI12-0272-1

Для подпрограмм параметров настройки можно задавать пре/пост условия, а для типов — аспект Default_Initial_Condition.

generic
   type Element is private
      with Default_Initial_Condition => Is_Empty (Element);

   with function Is_Empty (Value : Element) return Boolean;

   with function Hash (Value : Element) return Hash_Type
      with Post => Hash'Result in 0 .. 99;
package Maps is

Пакеты для больших чисел

AI12-0208-1

Два новых пакета

  • Ada.Numerics.Big_Numbers.Big_Integers
    • тип Optional_Big_Integer
    • подтипы Optional_Big_Positive, Optional_Big_Natural
    • подтипы Big_Integer, Big_Positive, Big_Natural
    • операции „+“, „-“, „*“, „/“, „**“, „abs“, „rem“, „mod“
    • преобразования в String, Integer, настраиваемые преобразования
  • Ada.Numerics.Big_Numbers.Big_Reals
    • тип Optional_Big_Real
    • подтипы Big_Real
    • операции „+“, „-“, „*“, „/“, „**“, „abs“
    • преобразования в String, Integer, Big_Integer, настраиваемые преобразования

Прочее

Множество вопросов носит технический либо узкоспециализированный характер. Для полноты приведу здесь лишь список таких изменений.

  • AI12-0002-1 Для Remote_Control_Interface типов нельзя определять свои процедуры чтения из потока и записи в поток.
  • AI12-0004-1 Ограничения на Unicode форму представления исходного кода.
  • AI12-0021-1 Wide_String при именах файлов, директорий, командной строке и пр.
  • AI12-0058-1 Обновление интерфейса с Фортраном
  • AI12-0059-1 Новый атрибут S'Object_Size
  • AI12-0075-1 Новый аспект Static для функций‐выражений.
  • AI12-0079-1 Аспекты описания побочный эффектов подпрограмм.
  • AI12-0086-1 Ослабили ограничение на дискриминант в агрегатах
  • AI12-0111-1 Неизменяемый вид для контейнеров позволяет выполнять чтение из разных потоков и ускоряет итерацию.
  • AI12-0112-1 Для описания контейнеров использовали контракты. Добавили возможность отключить их проверку.
  • AI12-0128-1 Атомарность доступа к полям записи
  • AI12-0140-1 Уточнения об ограничениях на type-view
  • AI12-0143-1 Индекс входа в пре/пост‐условиях
  • AI12-0144-1 Упрощение использования функции Random
  • AI12-0155-1 О правилах заморозки неполных описаний типов
  • AI12-0156-1 Разрешили анонимные ссылочные типы в итераторах
  • AI12-0160-1 Исправили правила для аспектов индексирования контейнеров
  • AI12-0162-1 Переписали правила Unchecked_Unions
  • AI12-0163-1 Новая политика Ordered_FIFO_Queuing
  • AI12-0164-1 Новый аспект Max_Entry_Queue_Length для входов
  • AI12-0165-1 Исправили правила для формальных подпрограмм и типов
  • AI12-0166-1 Исправили правила для предусловий и параметров по умолчанию в защищённых типах
  • AI12-0167-1 Про дырки в инвариантах типов
  • AI12-0168-1 Про заморозку в теле настраиваемого модуля
  • AI12-0169-1 Добавили аспекты для тела входа
  • AI12-0170-1 Абстрактные функции в предусловиях надклассовых операций
  • AI12-0171-1 Про семантику Synchronous_Task_Control
  • AI12-0172-1 Разрешили выражения возбуждения исключений для limitied
  • AI12-0173-1 Переформулировали правила расширенного оператора возврата
  • AI12-0174-1 Переформулировали правила Unchecked_Unions агрегатов
  • AI12-0175-1 Упростили задание адресов в 'Address
  • AI12-0178-1 Поправили ошибки в примерах
  • AI12-0179-1 О постусловиях в стандартных пакетах
  • AI12-0180-1 О использовании входов в инвариантах
  • AI12-0181-1 О влиянии аспектов на заморозку
  • AI12-0182-1 О защищённых операциях в предусловиях
  • AI12-0183-1 Редакционные правки
  • AI12-0184-1 Новые long типы в Interfaces.C
  • AI12-0185-1 Переформулировали правила для F'Result
  • AI12-0186-1 О заморозке профиля атрибутом S'Access
  • AI12-0187-1 Новый аспект Stable_Properties
  • AI12-0191-1 Уточнения для инварианта типа
  • AI12-0192-1 О инициализации защищённых типов
  • AI12-0193-1 О срабатывании постусловий на задачных входах
  • AI12-0194-1 О аспектах языка для тела входа
  • AI12-0195-1 О наследуемых подпрограммах и пре/пост‐условиях
  • AI12-0196-1 Разрешили непересекающийся доступ к элементам контейнера из нескольких задач одновременно
  • AI12-0198-1 Поправили правила постусловий
  • AI12-0199-1 Поправили правила о надклассовых инвариантах
  • AI12-0200-1 Поправили правила о одновременном вызове стандартных подпрограмм
  • AI12-0201-1 Отнесли операции со строками к статическим операциям
  • AI12-0203-1 О переопределении аспектов
  • AI12-0204-1 О префиксных видах
  • AI12-0206-1 О переопределении аспектов
  • AI12-0207-1 О соглашениях о вызове для анонимных типов
  • AI12-0211-1 О наследовании аспектов от интерфейсов
  • AI12-0213-1 Можно писать end record Name;
  • AI12-0216-1 О передаче составных значений в параметрах подпрограмм
  • AI12-0217-1 Переформулировали правила для X'Old
  • AI12-0219-1 О 'in' параметрах импортируемых подпрограмм
  • AI12-0220-1 Пре/пост‐условия для ссылочных типов
  • AI12-0222-1 О аспектах приватного типа
  • AI12-0224-1 О взаимодействии с Фортраном через C механизм
  • AI12-0225-1 Об использовании универсальных типов в атрибутах
  • AI12-0226-1 Поправили правила о преобразованиях типов
  • AI12-0227-1 Об операциях над универсальными типами
  • AI12-0228-1 О свойствах квалифицированных выражений
  • AI12-0230-1 Deadline Floor Protocol — замена Stack Resource Protocol.
  • AI12-0231-1 Про результат Activation_Is_Complete (Null_Task_Id)
  • AI12-0232-1 О «чистых» телах настраиваемых модулей
  • AI12-0235-1 Пакет System.Storage_Pools теперь «чистый»
  • AI12-0237-1 Новые атрибуты Representation и Value_From_Representation
  • AI12-0241-1 Аспект Nonblocking для стандартных подпрограмм
  • AI12-0244-1 О подавлении Range_Check для атрибутов S'Value
  • AI12-0247-1 Про Detect_Blocking и вложенные вызовы
  • AI12-0252-1 Про прерывания в Ravenscar профиле
  • AI12-0254-1 Новый стандартный контейнер Bounded_Indefinite_Holders
  • AI12-0256-1 Новый аспект No_Controlled_Parts
  • AI12-0258-1 Про инициализацию контейнеров
  • AI12-0259-1 Про строки возвращаемые Ada.Command_Line
  • AI12-0260-1 Новые функции Is_Basic и To_Basic в Wide_Characters.Handling
  • AI12-0261-1 Поправили правила о «private with»
  • AI12-0263-1 Про ссылки на стандарт Unicode
  • AI12-0264-1 Про сдвиги и ротацию бит
  • AI12-0265-1 Новый аспект Default_Initial_Condition
  • AI12-0267-1 Новая прагма Conflict_Check_Policy для контроля за параллельным исполнением.
  • AI12-0269-1 Аспект No_Return для функций
  • AI12-0276-1 Новая прагма Admission_Policy для спинлоков
  • AI12-0277-1 Про accessibility level параметров
  • AI12-0278-1 О неявном преобразовании анонимных типов
  • AI12-0279-1 Новый аспект Yield для невытесняющей диспетчеризации
  • AI12-0281-1 Защищённому объекту можно назначить конкретный ЦПУ.
  • AI12-0282-1 В типах параметров настройки можно указывать Atomic, Volatile и пр.
  • AI12-0283-1 Дистанционную подпрограмму и тип нельзя объявить Nonblocking
  • AI12-0285-1 Исправили синтаксис Stable_Properties
  • AI12-0286-1 Добавили аспект Allows_Exit в стандрантные пакеты
  • AI12-0287-1 О использовении not null в переименовании
  • AI12-0289-1 О неявном not null в анонимных типах
  • AI12-0290-1 Новое ограничение Pure_Barriers
  • AI12-0291-1 Новый профиль Jorvik, не такой жесткий, как Ravenscar
  • AI12-0292-1 Редакционные правки
  • AI12-0293-1 Новый пакет FIFO_Streams
  • AI12-0294-1 Редакционные правки
  • AI12-0298-1 Уточнения для прагма Conflict_Check_Policy
  • AI12-0299-1 Про дополнительные политики вытеснения задач
  • AI12-0300-1 Про умножение фиксированной точки на целое
  • AI12-0301-1 Исправления для Default_Value
  • AI12-0303-1 Про Global для констант
  • AI12-0304-1 Атрибут Image для предопределенных в языке типов
  • AI12-0306-1 Правка синтаксиса для агрегатов пустых массивов
  • AI12-0307-1 Правка правил разрешения имен для агрегатов
  • AI12-0308-1 Поправки к перечню конструкций‐определений
  • AI12-0309-1 Поправки к прагме Suppress
  • AI12-0310-1 Можно указывать приватную часть пакета в Global
  • AI12-0311-1 О подавлении проверки контрактов в предопределенных пакетах
  • AI12-0313-1 Введение в стандарт Ада 2020 вообщем
  • AI12-0314-1 Корректировка заголовка 13.13.1
  • AI12-0315-1 Описание для атрибута Image
  • AI12-0317-1 Упрощение некоторых правил
  • AI12-0318-1 Запретить Ada.Directories в No_IO
  • AI12-0319-1 О влиянии пулов памяти на Nonblocking у типов
  • AI12-0320-1 Редакционные правки
  • AI12-0322-1 Уточнения для символа @
  • AI12-0323-1 Уточнения об указании CPU для защищенных типов
  • AI12-0324-1 Редакционные правки
  • AI12-0325-1 Уточнения о литералах определенных пользователем
  • AI12-0327-1 Уточнения о фильтрах итераторов
  • AI12-0328-1 Уточнения в 4.5.2(28.1/4)
  • AI12-0329-1 Переименование FIFO_Streams пакетов
  • AI12-0330-1 Пополнение глоссария
  • AI12-0331-1 Порядок финализации подпулов
  • AI12-0332-1 Уточнения для Default_Initial_Condition

На этом пока всё.


Август 2018 — Декабрь 2018