Copyright (C) А.Гавва V-0.4w май 2004

6. Подпрограммы

В Аде, также как и во всех современных языках программирования, подпрограммы позволяют программисту группировать инструкции в самостоятельные, логически законченные алгоритмические единицы, которые, в последствии, могут быть вызваны и выполнены в любом месте программы. Они являются элементарным базовым средством для повторного использования кода и разделения одной большой задачи на самостоятельные подзадачи меньшего размера (декомпозиция). Использование подпрограмм позволяет уменьшить как общий размер исходных текстов программы, так и общий размер результирующих исполняемых файлов. Таким образом, применение подпрограмм облегчает общее управление проектом и упрощает его сопровождение.

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

6.1 Общие сведения о подпрограммах

Также как и в Паскале, подпрограммами Ады являются процедуры и функции.

Подпрограммы могут иметь параметры различных типов или не иметь ни одного параметра. При описании механизмов передачи параметров, как правило, используются следующие понятия:

формальный параметр    Параметр который используется при описании подпрограммы (процедуры или функции).
  
фактический параметр    Объект, который передается в подпрограмму при вызове подпрограммы. В качестве фактического параметра подпрограммы может быть передано целое выражение, при этом режимом передачи параметра не может быть режим "out".

Каждый формальный параметр подпрограммы имеет имя, тип и режим передачи.

Подпрограммы могут содержать локальные описания типов, подтипов, переменных, констант, других подпрограмм и пакетов.

Подпрограмма Ады, как правило, состоит из двух частей: спецификации и тела. Спецификация описывает интерфейс обращения к подпрограмме, другими словами - "что" обеспечивает подпрограмма. Тело подпрограммы описывает детали реализации алгоритма работы подпрограммы, то есть, "как" подпрограмма устроена.

Разделение описания подпрограммы на спецификацию и тело не случайно, и имеет большое значение. Такой подход позволяет предоставить пользователю подпрограммы только ее спецификацию и оградить, и даже избавить его от деталей реализации подпрограммы.

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

Необходимо заметить, что спецификации подпрограмм, как правило, помещаются в спецификации пакетов, а тела подпрограмм - в тела пакетов.

Кроме того, подпрограмма может быть самостоятельным независимым программным модулем. В этом случае, спецификация и тело подпрограммы помещаются в разные файлы (в файл спецификации и в файл тела, соответственно). Следует также заметить, что помещать спецификацию в отдельный файл, когда подпрограмма не является самостоятельной единицей компиляции не обязательно. В этом случае, спецификация подпрограммы может отсутствовать.

6.1.1 Процедуры

Процедуры Ады подобны процедурам Паскаля и используются для реализации самых разнообразных алгоритмов.

Общий вид описания процедуры выглядит следующим образом:

    procedure имя_процедуры [ (формальные_параметры) ] ;
       спецификация процедуры, определяющая имя процедуры и профиль ее формальных параметров (если они есть)

Общий вид тела процедуры:

    procedure имя_процедуры [ (формальные_параметры) ] is
       спецификация процедуры, определяющая имя процедуры и профиль ее формальных параметров (если они есть)
            
        . . .
      описательная (или декларативная) часть, которая может содержать локальные описания типов, переменных, констант, подпрограмм...
            
    begin 
        
        . . .
       исполняемая часть процедуры, которая описывает алгоритм работы процедуры;
    обязана содержать хотя бы одну инструкцию
            
    end [ имя_процедуры ];
       здесь, указание имени процедуры опционально

Таким образом, описание содержит только спецификацию процедуры и определяет правила ее вызова (иначе - интерфейс), а тело содержит спецификацию и последовательность инструкций, которые выполняются при вызове процедуры.

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

    
    
    procedure Demo(X: Integer; Y: Float) is
    begin
        null; -- пустая инструкция
    end Demo;
    

Вызов процедуры производится также как и в языке Паскаль, например:

    
    
    Demo(4, 5.0);
    

Необходимо также заметить, что Ада предоставляет программисту возможность, при необходимости, помещать в любых местах внутри исполнительной части процедуры инструкцию возврата из процедуры - return.

6.1.2 Функции

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

Общий вид описания функции выглядит следующим образом:

    function имя_функции [ (формальные_параметры) ]
        return тип_возвращаемого_значения ;
       спецификация функции, определяющая имя функции, профиль ее формальных параметров (если они есть) и тип возвращаемого значения

Общий вид тела функции:

    function имя_функции [ (формальные_параметры) ]
        return тип_возвращаемого_значения is
       спецификация функции, определяющая имя функции, профиль ее формальных параметров (если они есть) и тип возвращаемого значения
            
        . . .
      описательная (или декларативная) часть, которая может содержать локальные описания типов, переменных, констант, подпрограмм...
            
    begin 
        
        . . .
       исполнительная часть функции, которая описывает алгоритм работы функции;
    обязана содержать хотя бы одну инструкцию возврата значения - return
            
    end [ имя функции ];
       здесь, указание имени функции опционально

Использование инструкции возврата значения - return очень похоже на то, что используется в языке Си, при этом, функция может иметь сколько угодно инструкций возврата значения.

Функция может быть вызвана как часть выражения в инструкции присваивания или как аргумент соответствующего типа при вызове другой функции или процедуры. Другими словами - функция, возвращающая значения заданного типа, может быть использована везде, где может быть использована переменная этого типа.

Хотя режимы передачи параметров в подпрограммы будут подробно рассмотрены несколько позже, здесь, необходимо сделать несколько важных замечаний, которые имеют значение для функций Ады.

Согласно традиций стандарта Ada83, для передачи параметров в функцию разрешается использовать только режим "in". Поэтому, функция, через свои параметры, может только импортировать данные из среды вызвавшей эту функцию. При этом, параметры функции не могут быть использованы для изменения значений переменных в среде вызвавшей функцию. Таким образом, в отличие от традиций языка Си, функции Ады не обладают побочными эффектами.

Стандарт Ada95 ввел новый режим для передачи параметров - access. Этот режим разрешается использовать для передачи параметров в функции. Следует заметить, что использование этого режима допускает написание функций обладающих побочными эффектами.

6.1.3 Локальные переменные

Как уже говорилось, подпрограммы (и процедуры, и функции) могут содержать локальные переменные. Такие переменные доступны только внутри подпрограммы и не видимы извне этой подпрограммы. Время жизни (время существования) таких переменных определяется временем жизни (временем выполнения) подпрограммы.

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

6.1.4 Локальные подпрограммы

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

    
    
    with Ada.Text_IO;          use Ada.Text_IO;
    with Ada.Integer_Text_IO;  use Ada.Integer_Text_IO;
    
    procedure Ive_Got_A_Procedure is
    
        X : Integer := 6;
        Y : Integer := 5;
    
        procedure Display_Values (Number : Integer) is
        begin
            Put (Number);
            New_Line;
        end Display_Values;
    
    begin
        Display_Values (X);
        Display_Values (Y);
    end Ive_Got_A_Procedure;
    

В этом примере область видимости процедуры Display_Values ограничивается процедурой Ive_Got_A_Procedure. Таким образом, процедура Display_Values "не видна" и не может быть вызвана из любого другого места.

6.1.5 Раздельная компиляция

В предыдущем примере, если будет произведено какое-нибудь изменение кода, то обе процедуры должны быть переданы компилятору (поскольку обе находятся в одном файле с исходным текстом). Мы можем разделить эти две компоненты, и поместить их в отдельные файлы, оставляя без изменения ограничения области видимости для процедуры Display_Values. Это несколько похоже на директиву #include, используемую в языке Си, но, в языке Ада, теперь оба файла становятся независимыми компилируемыми модулями.

В первом файле:

    
    
    with Ada.Text_IO;         use Ada.Text_IO;
    with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
    
    procedure Ive_Got_A_Procedure is 
    
        X : Integer := 6;
        Y : Integer := 5;
    
        procedure Display_Values(Number : Integer) is separate;
    
    begin
        Display_Values(X);
        Display_Values(Y);
    end Ive_Got_A_Procedure;
    

Во втором файле:

    
    
    separate(Ive_Got_A_Procedure)  -- примечание! нет завершайщего символа
                                   -- точки с запятой
    
    procedure Display_Values(Number : Integer) is
    begin
        Put(Number);
        New_Line;
    end Display_Values;
    

Выделенный в самостоятельный файл (и ставший отдельно компилируемым модулем), код - идентичен тому, что было в предыдущей версии. Однако теперь, если будет изменена только внутренняя подпрограмма, то только она должна быть подвергнута перекомпиляции компилятором. Это также позволяет разделить программу на несколько частей, что может облегчить ее понимание.

6.1.6 Подпрограммы как библиотечные модули

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

Рассмотрим как это делается на примере процедур Ive_Got_A_Procedure и Display_Values, из предыдущего примера о раздельной компиляции. Теперь, процедура Display_Values будет оформлена как самостоятельный библиотечный подпрограммный модуль, а процедура Ive_Got_A_Procedure будет ее использовать.

В этом случае, полное описание процедуры Display_Values будет состоять из двух файлов: файла спецификации и файла тела процедуры.

Файл спецификации процедуры Display_Values (display_values.ads) будет иметь следующий вид:

    
    
    procedure Display_Values(Number : Integer);
    

Файл тела процедуры Display_Values (display_values.adb) будет иметь следующий вид:

    
    
    with Ada.Text_IO;         use Ada.Text_IO;
    with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
    
    procedure Display_Values(Number : Integer) is
    begin
        Put(Number);
        New_Line;
    end Display_Values;
    

Третий файл - это файл тела процедуры Ive_Got_A_Procedure (ive_got_a_procedure.adb). В этом случае он будет иметь следующий вид:

    
    
    with Ada.Text_IO;         use Ada.Text_IO;
    with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
    with Display_Values;
    
    procedure Ive_Got_A_Procedure is 
    
        X : Integer := 6;
        Y : Integer := 5;
    
    begin
        Display_Values(X);
        Display_Values(Y);
    end Ive_Got_A_Procedure;
    

Примечательно, что теперь, в файле тела процедуры Ive_Got_A_Procedure, процедуру Display_Values, которая оформлена как самостоятельный библиотечный модуль, необходимо указать в спецификаторе совместности контекста with.

Также, необходимо заметить, что подпрограммы, оформленные как самостоятельные библиотечные модули, не указываются в спецификаторе использования контекста use.

6.2 Режимы передачи параметров

Стандарт Ada83 предусматривал три режима передачи параметров для подпрограмм:

Стандарт Ada95 добавил еще один режим передачи параметров:

Все эти режимы не имеют непосредственных аналогов в других языках программирования. Необходимо также отметить следующее:

Для "in" / "out" скалярных значений используется механизм передачи параметров по копированию-"in" (copy-in), по копированию-"out" (copy-out). Стандарт специфицирует, что любые другие типы могут быть переданы по copy-in/copy-out, или по ссылке.

Ada95 указывает, что лимитированные приватные типы (limited private types), которые рассматриваются позднее, передаются по ссылке, для предотвращения проблем нарушения приватности.

6.2.1 Режим "in"

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

Это значит, что при входе в подпрограмму, формальный параметр инициализируется значением фактического параметра, при этом, внутри подпрограммы, он является константой и разрешает только чтение значения ассоциированного фактического параметра.

    
    
    with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
    
    procedure Demo(X : in Integer; Y : in Integer) is
    begin
        X := 5;   -- недопустимо, in параметр доступен только по чтению
        Put(Y);
        Get(Y);   -- также недопустимо
    end Demo;
    

Режим "in" разрешается использовать и в процедурах, и в функциях.

6.2.2 Режим "in out"

Этот режим непосредственно соответствует параметрам передаваемым по ссылке (подобно var-параметрам языка Паскаль).

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

    
    
    procedure Demo(X : in out Integer;
                   Y : in     Integer) is
    
        Z : constant Integer := X;
    
    begin
        X := Y * Z; -- это допустимо!
    end Demo;
    

Режим "in out" разрешается использовать только в процедурах.

6.2.3 Режим "out"

В этом режиме, при входе в подпрограмму, формальный параметр не инициализируется (!!!) значением фактического параметра. Согласно стандарта Ada95, внутри подпрограммы, формальный параметр, использующий этот режим, может быть использован как в левой, так и в правой части инструкций присваивания (другими словами: формальный параметр доступен как для чтения, так и для записи). Согласно стандарта Ada83, внутри подпрограммы, такой формальный параметр может быть использован только в левой части инструкций присваивания (другими словами: доступен только для записи). При этом, после выхода из подпрограммы, значение фактического параметра заменяется на значение формального параметра.

    
    
    procedure Demo(X : out Integer;
                   Y : in Integer) is
    
        -- при входе в подпрограмму X не инициализирован!!!
    
    begin
        X := Y;
    end Demo;
    

Режим "out" разрешается использовать только в процедурах.

6.2.4 Режим access

Поскольку значения ссылочного типа (указатели) часто используются в качестве параметров передаваемых подпрограммам, Ада предусматривает режим передачи параметров access, который специально предназначен для передачи параметров ссылочного типа. Заметим, что подробному обсуждению ссылочных типов Ады далее посвящена самостоятельная глава - "Ссылочные типы (указатели)". Необходимо также обратить внимание на то, что режим передачи параметров access был введен стандартом Ada95 и он отсутствует в стандарте Ada83.

При использовании режима access, фактический параметр, который предоставляется при вызове подпрограммы, - это любое значение ссылочного типа, которое ссылается (указывает) на объект соответствующего типа. При входе в подпрограмму, формальный параметр инициализируется значением фактического параметра, при этом, Ада производит автоматическую проверку того, что значение параметра не равно null. В случае когда значение параметра равно null генерируется исключительная ситуация Constraint_Error (проще говоря, - ошибка). Внутри подпрограммы, формальный параметр, использующий режим access, является константой ссылочного типа и ему нельзя присваивать новое значение, поэтому такие формальные параметры несколько подобны формальным параметрам, использующим режим "in". Однако, поскольку параметр является значением ссылочного типа (указателем), то подпрограмма может изменить содержимое объекта на который данный параметр ссылается (указывает). Кроме того, внутри подпрограммы такой параметр принадлежит анонимному ссылочному типу, и поскольку у нас нет возможности определить имя этого ссылочного типа, то мы не можем описать ни одного дополнительного объекта этого типа. Любая попытка конвертирования значения такого параметра в значение именованого ссылочного типа будет проверяться на соответствие правилам области действия для ссылочных типов. При обнаружении нарушения этих правил генерируется исключительная ситуация Programm_Error.

    
    
        . . .
    
    function Demo_Access(A : access Integer) return Integer is
    begin
        return A.all;
    end Demo_Access;
    
        . . .
    
    type  Integer_Access  is access Integer;
    
    Integer_Access_Var  : Integer_Access := new Integer'(1);
    Aliased_Integer_Var : aliased Integer;
    
        . . .
    
    X : Integer := Demo_Access(Integer_Access_Var);
    Y : Integer := Demo_Access(Aliased_Integer_Var'Access);
    Z : Integer := Demo_Access(new Integer);
    
        . . .
    

Режим access разрешается использовать и в процедурах, и в функциях.

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

6.3 Сопоставление формальных и фактических параметров

6.3.1 Позиционное сопоставление

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

    
    
    procedure Demo(X : Integer; Y : Integer);  -- спецификация процедуры
    
      . . .
    
    Demo(1, 2);
    

В этом случае, фактический параметр 1 будет подставлен вместо первого формального параметра X, а фактический параметр 2 будет подставлен вместо второго формального параметра Y.

6.3.2 Именованное сопоставление

Для улучшения читабельности вызовов подпрограмм (а Ада разрабатывалась с учетом хорошей читабельности) Ада позволяет использовать именованное сопоставление формальных и фактических параметров. В этом случае мы можем ассоциировать имя формального параметра с фактическим параметром. Это свойство делает вызовы подпрограмм более читабельными.

    
    
    procedure Demo(X : Integer; Y : Integer);  -- спецификация процедуры
    
      . . .
    
    Demo(X => 5, Y => 3 * 45);   -- именованное сопоставление
                                 -- формальных и фактических
                                 -- параметров при вызове
    

Расположение списка параметров вертикально, также способствует улучшению читабельности.

    
    
    Demo(X => 5,
         Y => 3 * 45);
    

Поскольку при именованом сопоставлении производится явное ассоциирование между формальными и фактическими параметрами (вместо неявного ассоциирования, используемого в случае позиционного сопоставления), то нет необходимости строго придерживаться того же самого порядка следования параметров, который указан в спецификации подпрограммы.

    
    
    Demo(Y => 3 * 45,    -- при именованом сопоставлении
         X => 5);        -- порядок следования параметров
                         -- не имеет значения
    

6.3.3 Смешивание позиционного и именованного сопоставления

Ада позволяет смешивать позиционное и именованное сопоставление параметров. В этом случае должно соблюдаться следующее условие: позиционно-ассоциированные параметры должны предшествовать параметрам, которые ассоциируются по имени.

    
    
    procedure Square(Result :    out Integer;
                     Number : in     Integer) is
    begin
        Result := Number * Number;
    end Square;
    

В результате, показанная выше процедура Square может быть вызвана следующими способами:

    
    
    Square(X, 4);
    Square(X, Number => 4);
    Square(Result => X, Number => 4);
    Square(Number => 4, Result => x);
    
    Square(Number => 4, X);  -- недопустимо, поскольку позиционно-ассоциируемый
                             -- параметр следует за параметром, ассоциируемым
                             -- по имени
    

6.4 Указание значения параметра по-умолчанию

Для любых "in"-параметров ("in" или "in out"), в спецификации подпрограммы можно указать значение параметра по-умолчанию. Синтаксис установки значения параметра по-умолчанию подобен синтаксису определения инициализированных переменных и имеет следующий вид:

    
    
    with Ada.Text_IO;        use Ada.Text_IO;
    
    procedure Print_Lines(No_Of_Lines: Integer := 1) is
    
    begin
        for Count in 1 .. No_Of_Lines loop
            New_Line;
        end loop;
    end Print_Lines;
    

Такое описание устанавливает значение параметра No_Of_Lines для случаев когда процедура Print_Lines вызывается без указания значения этого параметра (позиционного или именованного).

Таким образом, вызов этой процедуры может иметь вид:

    
    
    Print_Lines;        -- это печатает одну строку
    Print_Lines(6);     -- переопределяет значение параметра
                        -- установленное по-умолчанию
    

Подобно этому, если процедура Write_Lines была описана как:

    
    
    with Ada.Text_IO;        use Ada.Text_IO;
    
    procedure Write_Lines(Letter      : in Char := '*';
                          No_Of_Lines : in Integer := 1) is
    
    begin
        for I in 1 .. No_Of_Lines loop
            for I in 1 .. 80 loop
                Put(Letter);
            end loop;
            New_Line;
        end loop;
    end Write_Lines;
    

то она может быть вызвана следующими способами:

    
    
    Write_Lines;                     -- для параметров Letter и No_Of_Lines
                                     -- используются значения устанавливаемые
                                     -- по-умолчанию
    Write_Lines('-');                -- значение по-умолчанию - для No_Of_Lines
    Write_Lines(no_of_lines => 5);   -- значение по-умолчанию - для Letter
    Write_Lines('-', 5)              -- оба параметра определены
    

6.5 Совмещение (overloading)

Поиск новых имен для подпрограмм, которые выполняют одинаковые действия, но с переменными разных типов, всегда является большой проблемой при разработке программного обеспечения. Хорошим примером для иллюстрации такой проблемы является процедура Insert.

В подобных случаях, для облегчения жизни программистам, Ада позволяет разным подпрограммам иметь одинаковые имена, предоставляя механизм который называется совмещением (overloading).

6.5.1 Совмещение подпрограмм (subprogram overloading)

Предоставляя механизм совмещения имен подпрограмм, Ада выдвигает единственное требование: подпрограммы должны быть распознаваемы (или различимы). Две подпрограммы, имеющие одинаковые имена, будут распознаваемы если они имеют разный "профиль". Профиль подпрограммы характеризуется количеством параметров и их типами, а также, если подпрограмма является функцией, - типом возвращаемого значения.

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

    
    
    procedure Insert(Item : Integer);  -- две процедуры с одинаковыми именами,
    procedure Insert(Item : Float);    -- но имеющие разный "профиль"
    

Примерами совмещенных подпрограмм могут служить процедуры Put и Get из стандартного пакета Ada.Text_IO.

6.5.2 Совмещение знаков операций (operator overloading)

В языках подобных Паскалю знак операции "+" - совмещен. Действительно, он может использоваться для сложения целых и вещественных чисел, и даже строк. Таким образом, очевидно что этот знак операции используется для представления кода который выполняет абсолютно разные действия.

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

Кроме того, к функциям которые реализуют действия знаков операций предъявляется дополнительное требование: они не могут быть выделены в самостоятельно компилируемые модули, а должны содержаться в другом модуле, таком как процедура, функция или пакет.

Рассмотрим простой пример в котором мы хотим предусмотреть возможность сложения двух векторов:

    
    
    procedure Add_Demo is
    
        type Vector is array (Positive range <>) of Integer;
        A : Vector(1..5);
        B : Vector(1..5);
        C : Vector(1..5);
    
        function "+"(Left, Right : Vector) return Vector is
    
            Result   : Vector(Left'First..Left'Last);
            Offset   : constant Natural := Right'First - 1;
    
        begin
            if Left'Length /= Right'Length then
                raise Program_Error;        -- исключение,
                                            -- рассматриваются позже
            end if;
    
            for I in Left'Range loop
                Result(I) := Left(I) + Right(I - Offset);
            end loop;
            return Result;
        end "+";
    
    begin
        A := (1, 2, 3, 4, 5);
        B := (1, 2, 3, 4, 5);
        C := A + B;
    end Add_Demo;
    

В этом примере хорошо продемонстрированы многие ранее рассмотренные средства которые характерны для языка программирования Ада.

6.5.3 Спецификатор "use type"

В случае когда какой-либо пакет содержит описания знаков операций, может быть использована несколько модифицированная форма спецификатора использования use, которая позволяет использовать описанные в этом пакете знаки операций без необходимости указания имени пакета в качестве префикса. При этом, в случае использования других компонентов, описанных в этом пакете, необходимость указания имени пакета в качестве префикса сохраняется. Эта модифицированная форма спецификатора использования имеет следующий вид:

    
    
    use type  имя_типа
    

Здесь, имя_типа указывает тип данных для которого знаки операций будут использоваться без указания имени пакета в качестве префикса.


Copyright (C) А.Гавва V-0.4w май 2004