Постоянный элемент в объекте ada?

В 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 будет использоваться во всех экземплярах, а я не хочу.

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

Пока что ответы - хорошие обходные пути. Но я думаю, что окончательный ответ, основанный на моем исследовании, проведенном на прошлой неделе, заключается в том, что это невозможно сделать на Аде. Мне просто нужно использовать один из обходных путей, упомянутых в ответах ниже.

Avi Chapman 16.09.2018 23:46
6
1
501
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Нет, не совсем так.

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

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;

Я бы не стал помещать всю скрытую информацию в пример кода; дискриминант Immutable также не может быть изменен, если тип является общедоступным.

flyx 10.09.2018 11:32

Может ли такой подход допускать и настраиваемые значения? То, что я нахожу сложным, состоит в том, что в одной и той же записи есть как только чтение, так и не только чтение.

Avi Chapman 10.09.2018 23:57

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

Jacob Sparre Andersen 11.09.2018 06:17

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

Jacob Sparre Andersen 11.09.2018 06:18

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

Ответ принят как подходящий

Прежде чем я отвечу на вопрос, вероятно, было бы полезно провести различие между моделированием объектов в Ada и Java / C#. В Java все является объектом, поэтому все константы должны быть final - в Ada все немного по-другому, объектная система Ada («тегированные типы» на языке Ada) построена на двух элементах: записях и наследовании типов. . Это означает, что при обучении ООП мы могли бы постепенно вводить сначала определение типа (например, Type Degree is new Integer;), затем записи (например, инкапсуляцию), затем private-типы (например, скрытие информации) и, наконец, объединение всего вместе с тегированными типами. .. все, о чем я предполагаю, вы знаете.

В Аде 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 - это Только этого типа.)

Другие вопросы по теме