#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.