Почему Ada не отслеживает эту проверку указанного диапазона?

#ada

#ada

Вопрос:

Я прохожу learn.adacore.com учебник и наткнулся на проблему, в которой я не уверен.

В частности, я понимаю, что Ada предназначена для отслеживания попыток переполнения переменной с указанным определением диапазона.

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

 with Ada.Text_IO; use Ada.Text_IO;

procedure Custom_Floating_Types is
    type T_Norm is new float range -1.0 .. 1.0;

    D : T_Norm := 1.0;
begin
    Put_Line("The value of D =" amp; T_Norm'Image(D));
    -- D := D   1.0; -- This causes a range check failure at run time = completely expected.
    Put_Line("The value of D =" amp; T_Norm'Image(D   1.0)); -- This doesn't?

end Custom_Floating_Types;
 

Ответ №1:

У вас есть пара довольно хороших ответов, но я собираюсь добавить еще один, потому что ясно, что вы ожидаете, что выражение D 1.0 вызовет исключение, а ответы, которые у вас есть, не объясняют, почему этого не происходит.

Объявление типа, подобное

 type T_Norm is new float range -1.0 .. 1.0;
 

примерно эквивалентно

 type T_Norm'Base is new Float;
subtype T_Norm is T_Norm'Base range -1.0 .. 1.0;
 

Типу (называемому «базовым типом») не присваивается имя, хотя на него часто можно ссылаться с 'Base помощью атрибута. Имя, которое присваивается подтипу, называется «подтип с первым именем».

Это различие важно, и ему часто не уделяется достаточного внимания. Как объяснил egilhh, T_Norm'Image определяется в терминах T_Norm'Base . Это также относится к арифметическим операторам. Например, " " определяется как

 function " " (Left : in T_Norm'Base; Right : in T_Norm'Base) return T_Norm'Base;
 

2.0 явно находится в диапазоне T_Norm'Base , поэтому оценка D 1.0 не нарушает никаких ограничений и не передает его T_Norm'Image . Однако, когда вы пытаетесь присвоить результирующее значение D , которое имеет подтип T_Norm , выполняется проверка того, что значение находится в диапазоне подтипа, и возникает исключение, поскольку проверка завершается неудачей.

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

 type A is array (1 .. 10) of C;
 

примерно эквивалентно

 type A'Base is array (Integer range <>) of C;
subtype A is A'Base (1 .. 10);
 

Если вы это сделаете

 V : A;
... V (2 .. 4)
 

вы можете ожидать проблем, потому что срез не имеет границ A . Но это работает, потому что у среза нет подтипа A , а скорее анонимный подтип A'Base (2 ..4) .

Комментарии:

1. Большое вам за это спасибо. Я еще не достиг такого уровня знаний Ada, но это дало гораздо более четкое понимание.

Ответ №2:

В определении «Изображение говорит:

Для каждого скалярного подтипа S:

S’Image обозначает функцию со следующей спецификацией:

функция S’Image(Arg : S’Base) возвращает строку

Как вы можете видеть, он принимает параметр базового (неограниченного) типа

Комментарии:

1. Спасибо за это. Я посмотрю на определение.

Ответ №3:

T_norm’Image(D 1.0) не присваивает и не считывает значение, выходящее за пределы диапазона. Он запрашивает атрибут изображения (строковое представление) для (D 1.0), что совпадает с запросом (1.0 1.0).

Я вижу два способа возникновения путаницы. Во-первых, имя «атрибут» может быть неверно истолковано, предполагая, что «Изображение включает в себя что-то, присущее D. Это не так. Атрибут ‘Image — это просто функция, поэтому D — это просто часть выражения, которое определяет значение параметра (в вашем примере = 2.0).

Во-вторых, атрибут ‘Image берется из Float . Таким образом, его параметром может быть любой Float .

Вы можете создать функцию, которая принимает только параметры T_NORM’Range, и сделать эту функцию атрибутом T_Norm . См. Справочное руководство Ada 4.10.

Комментарии:

1. RM 4.10 еще не существует. Это только часть черновика RM для предстоящего пересмотра языка, получившего название Ada 202x

2. Я предполагал, что это был какой-то атрибут для D, отсюда и путаница. Спасибо всем, кто помог. Я проверю определения в будущем.

Ответ №4:

Потому что вы не сохраняете значение, превышающее range в D.