Прежде чем я отвечу на вопрос, вероятно, было бы полезно различить моделирование объектов Ada и Java / C #. В Java все является объектом, и поэтому все константы должны быть final
- в Ada все немного иначе, объектная система Ada («тегированные типы» на языке Ada) построена на двух элементах: записи и тип -дифференцирование. Это означает, что при обучении ООП мы могли бы постепенно вводить сначала вывод типов (например, Type Degree is new Integer;
), затем записи (т.е. инкапсуляцию), затем private
-типы (т.е. скрытие информации) и, наконец, объединить все вместе с tagged-types ... все из которых я предполагаю, что вы осведомлены.
В Аде constant
- это всего лишь некоторый объект, который может быть прочитан, но [обычно] не записан. (Вещи могут быть смешными, например, с отображенным в память вводом-выводом.) Таким образом, мы могли бы сказать:
Package Ex1 is
Type Stub1 is private; -- Some type, with almost nothing public.
C1 : Constant Stub1; -- A constant of that type.
Private
Type Stub1 is tagged record
Data_1 : Integer;
Data_2 : Float;
end;
-- And now we can tell the compiler what C1 _is_.
C1: Constant Stub1 := (Data_1 => 3, Data_2 => 1.2);
End Ex1;
Вот так мы бы сделали константу для тегового типа, сохраняя детали его реализации скрытыми; хотя, по общему признанию, мы могли разоблачить все и избавиться от всего раздела private
.
Теперь мы переходим к интересной функции записей [и теговых типов], называемой дискриминантами - они похожи на константы и похожи на универсальные типы в других языках. С дискриминантами мы можем создать тип сообщения, размер которого зависит от длины сообщения:
Package Ex2 is
Type Message(Length : Natural) is private; -- A message.
Function Create( Text : String ) return Message;
Private
Type Message(Length : Natural) is record
Data : String(1..Length) := (Others => ' '); -- Defaults to space-filled string.
end;
Function Create( Text : String ) return Message is
( Data => Text, Length => Text'Length );
End Ex2;
Теперь, в этом случае, когда вы делаете присваивание, подобное X : Message := Create("Steve");
, тип переменной [неограниченный, в этом примере, становится ограниченным в этом случае Message(5)
(потому что "Стив" - 5 символов) и поэтому пытается переназначение с помощью строки сообщения другого размера не сработает. (Таким образом, хотя вы не можете сказать X:= Create("Why")
, вы можете сказать X:= Create("Hello")
, потому что дискриминант [Length
] здесь равен 5.) - Таким образом, дискриминанты могут действовать как постоянные поля в некоторых случаях.
Ключевое слово limited
означает, что тип не имеет присваивания [но имеет инициализацию], поэтому вы могли бы заставить весь тип вести себя как константа; это отличается от того, что один компонент будет constant
, хотя, безусловно, не так тонко, как различие между T
и T'Class
(T'Class
- это Тип T
и все производные от него типы, где как T
только этого типа.)