Ада-95. Компилятор GNAT

       

Типы и подтипы


Как уже говорилось, концепция типа является в Аде основопологающим фактором создания надежного программного обеспечения. Предположим, что у нас есть два целочисленных типа, которые как-то характеризуют "звоночки" и "свисточки", и мы никак не хотим смешивать эти понятия. Нам необходимо, чтобы компилятор имел возможность предупредить нас: "Ба, да вы пытаетесь смешать выши "звоночки" и "свисточки"! Что Вы в действительности подразумеваете?". Это выглядит излишними осложнениями для людей, которые используют другие языки программирования со слабой типизацией данных. Размышления над тем какие данные необходимо представить, описание различных типов данных и правил конвертирования типов требуют некоторых усилий. Однако, такие усилия оправдываются тем, что как только это сделано, компилятор сможет помочь отыскать разные глупые ошибки.

Бывают случаи, когда нам необходимо указать, что какие-то переменные могут хранить только какое-то ограниченное число значений предоставляемых определенным типом данных. При этом, мы не хотим описывать самостоятельный новый тип данных, поскольку это потребует явного указания правила преобразования типа при взаимодействии со значениями, которые имеют оригинальный тип данных, то есть нам необходима возможность смешивать различные типы, которые, по своей сути, являются одинаковыми сущностями, но при этом имеют некоторые различия в своих характеристиках. К тому же, мы хотим сохранить преимущества проверки корректности наших действий, которые предоставляет компилятор. В таких случаях, Ада позволяет нам описывать подтипы (subtype) существующих типов данных (это соответствует типам определяемым пользователем в Паскале).

Общий синтаксис объявления подтипа имеет вид:

subtype Name_1 is Base_Type; -- в данном случае, Name_1 является -- синонимом типа Base_Type

subtype Name_2 is Base_Type range Lowerbound..Upperbound;

Примеры объявления подтипов приводятся ниже:

type Processors is (M68000, i8086, i80386, M68030, Pentium, PowerPC); subtype Old_Processors is Processors range M68000..i8086; subtype New_Processors is Processors range Pentium..PowerPC;

subtype Data is Integer; subtype Age is Data range 0..140; subtype Temperatures is Float range -50.0..200.0; subtype Upper_Chars is Character range 'A'..'Z';

<




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

My_Age : Age; Height : Integer;

Height := My_Age; -- глупо, но никогда не вызывает проблем

My_Age := Height; -- может вызвать проблемы, когда значение типа Height

-- будет за пределами диапазона значений My_Age (0..140), -- но при этом остается совметимым

Чтобы избежать генерацию исключительной ситуации, можно использовать проверки принадлежности диапазону ("in" и/или "not in"). Например:

I : Integer; N : Natural;

. . .

if I in Natural then

N := I else

Put_Line ("I can't be assigned to N!"); end if;

. . .

Реально, все типы Ады являются подтипами анонимных типов, рассматриваемых как их базовые типы. Поскольку базовые типы анонимны, то на них нельзя ссылаться по имени. При этом, для получения базового типа можно использовать атрибут 'Base. Например, Integer'Base - это базовый тип для Integer. Базовые типы могут иметь или могут не иметь диапазон значений больший чем их подтипы. Это имеет значение только в выражениях вида "A * B / C" которые, при вычислении промежуточных значений, используют базовый тип. То есть, результат "A * B" может выходить за пределы значений типа не приводя к генерации исключительной ситуации если общий результат вычисленного значения всего выражения будет находиться в допустимом диапазоне значений для данного типа.

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


Содержание раздела