Постоянный элемент в объекте Ada? - PullRequest
0 голосов
/ 10 сентября 2018

В Java или C # у вас часто бывают члены класса final или readonly - они устанавливаются один раз, а затем никогда не затрагиваются. Они могут содержать разные значения для разных экземпляров класса.

Есть ли что-то похожее в Аде? Я попытался создать нечто подобное в Аде таким образом:

package MyPackage is

   type MyObject is limited new OtherPackage.Object with private;

....

private

   type MyObject (...) is limited new OtherPackage.Object with
      record
         M_MyField : Integer := 10;
         M_MyConstantFactory : constant Factory.Object'Class := new Factory.Object;
      end record;

end MyPackage;

Сбой при объявлении M_MyConstantFactory, говорящем constant components are not permitted. Это можно обойти? Коллега предложил объявить его где-то еще в пакете, но это означало бы, что один M_MyConstantFactory будет использоваться всеми экземплярами, а это не то, что мне нужно.

Нужно ли просто признать, что можно изменить установленное значение и вручную защититься от этого?

Ответы [ 3 ]

0 голосов
/ 15 сентября 2018

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

0 голосов
/ 29 сентября 2018

Прежде чем я отвечу на вопрос, вероятно, было бы полезно различить моделирование объектов 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 только этого типа.)

0 голосов
/ 10 сентября 2018

Нет. Не совсем.

Если ваш компонент имеет дискретный тип или тип доступа, вы можете сделать его дискриминантом и тем самым сделать его неизменным.

with Ada.Integer_Text_IO;

procedure Immutable_Components is

   type Instance (Immutable : Positive) is null record;

   A : Instance := (Immutable => 1);

begin
   Ada.Integer_Text_IO.Put (A.Immutable);

   --  A.Immutable := 2; --  assignment to discriminant not allowed:
end Immutable_Components;
...