===== 2.9 Введение в атрибуты параметров ===== ==== 1. Понятие о атрибутах ==== Атрибуты — это информационные признаки (свойства) объектов. Например, атрибут солдата — автомат. А атрибут почтальона — специальная сумка для писем и газет. По сути, атрибуты — это свойства. И часть свойств переменных и процедур программы выносится за понятие свойства во многих распространённых компилируемых языках (например, Си или Ассемблер), так как на этапе исполнения программе либо не нужно знать об этих свойствах, либо узнать о них она не может (ограниченные свойства интроспекции — возможности программы рассматривать своё устройство во время работы). Атрибуты параметров в КП играют важную роль, которая связана с компонентностью. Они позволяют задать правила взаимодействия частей программы, как во время её написания, так и во время её работы. Атрибуты параметров (переменных процедур) частично относятся к метаинформации (информации выходящей за рамки самой программы, это как бы надинформация). В официальной информации по языку Компонентный Паскаль атрибуты называются описатели (несколько общее понятие, так как сама программа является тем же описателем). [↑] ==== 2. Процедура с параметрами без атрибутов ==== Такой тип процедур был рассмотрен многократно. Например, в процедуре Start* нет никаких параметров, и это допустимо. Но чаще можно встретить объявление процедур в виде: PROCRDURE GetVal(val: INTEGER); PROCEDURE ResetStatus(status: tStatus; exit_code: tExitCode); Параметры, у которых нет никаких атрибутов, кроме описателя их типа в КП принято называть параметры-значения. Внутри процедур с такими параметрами можно делать всё, что угодно, они не изменяют значение исходной переменной, так как копии аргументов создаются локально при вызове процедуры. Их можно вернуть вызывающему участку кода с помощью оператора RETURN. Поскольку на вход процедуры что-то должно быть передано обязательно — начальное значение не инициализируется, в отличии от глобальных переменных, которые инициализуруются нулём, либо NIL, либо строкой с нулевой длиной. [↑] ==== 3. Атрибут IN ==== Атрибут IN используется в КП чтобы была возможность использовать параметры-переменные в процедурах только на чтение. Причём атрибут IN может быть применён только для записей или массивов. Это своего рода задаваемая пользователем составная/массивовая константа уровня процедуры сложного типа (т. е. не базового — INTEGER, REAL, CHAR и т. д.). Пример использования: MODULE TestTest_in; IMPORT Log, Math; PROCEDURE Do(IN a:INTEGER); VAR BEGIN Log.Int(a);Log.Ln; a:=3; Log.Int(a);Log.Ln; END Do; BEGIN END TestTest_in. Как видно из примера, при попытке его скомпилировать, посыпятся сообщения об ошибках. И всё именно потому, что параметр с атрибутом IN доступен только для чтения. К тому же, параметр "а" определён как INTEGER, а допустимые типы — записи или массивы. [↑] ==== 4. Атрибут OUT ==== Может возникнуть необходимость возвращать какие-либо данные из процедуры. Нет никаких проблем, если такой параметр один. Можно использовать ключевое слово RETURN. Если необходимо возвращать множество однотипных значений, можно вернуть ссылку на массив. Что делать, если требуется вернуть несколько значений разных типов? Вот тут и приходит на помощь атрибут параметра процедуры OUT. Посколько такие параметры работают только "на выход", OUT-параметры, как и локальные переменные устанавливаются компилятором в NIL, если это указательные или процедурные типы. Если это другие типы, то надо позаботиться, чтобы процедура возвращала правильные значения (а иначе зачем вообще описывать OUT-параметры?). Пример ниже показывает как работать с такими параметрами: MODULE TestTest_out; IMPORT Log, Math; PROCEDURE Do(OUT z:INTEGER; r:REAL); VAR BEGIN z:=5; r:=-1; END Do; PROCEDURE Start*; VAR BEGIN Do(0,0) END; BEGIN END TestTest_out. Как видно из примера, попытка скомпилировать модуль, с вызовом пройцедуры Do закончилась крахом, так как, в качестве аргументов передаются константы, а не переменные. По возврате из процедуры, чему присваивать возвращаемые значения? В примере, представленном ниже, все ошибки устранены и модуль успешно компилируется: MODULE TestTest_out; IMPORT StdLog, Math; PROCEDURE Do (OUT z: INTEGER; r: REAL); VAR BEGIN z := 5; r := - 1; END Do; PROCEDURE Start*; VAR z1: INTEGER; r1: REAL; BEGIN Do(z1, r1); StdLog.Int(z1); StdLog.Ln; StdLog.Real(r1); StdLog.Ln; END Start; BEGIN END TestTest_out. (!)TestTest_out.Start Оператор RETURN мог бы возвращать несколько значений, во многих языках программирования такой функционал реализован. Но лучше оператор RETURN рассматривать как оператор управления потоком, с возможностью возврата кода выполнения операции, а не штатную возможность возвращать результат операций. Также стоит отметить, что возврат результата требует больше накладных расходов, чем непосредственное изменение переменной. Отсюда следует понимать для чего нужны OUT-параметры и ключевое слово RETURN: * если нужно вернуть одиночный результат функции и присвоить его переменной, используем RETURN; * если нужно изменить в процедуре несколько разнотипных переменных, без лишних присвоений, выделения памяти под локальные переменные на стеке, освобождения этой памяти после присовения значений, используем OUT-параметры. [↑] ==== 5. Атрибут VAR ==== Этот атрибут параметра процедуры позволяет делать с передаваемой переменной всё что угодно. Как принято называть такую передачу в программировании: по ссылке. Все изменения произведённые над такой переменной будут отражены на той переменной, которая была указана в качестве аргумента параметра процедуры. VAR-параметры подобны гуляй-ветру в поле: отследить изменение переменной становится гораздо сложнее, и для контроля за её значением следует использовать контрольные инструкции (использовать эти инструкции, вообще говоря, хороший тон в программировании), речь о которых пойдёт в отдельной главе. Также стоит отметить, что атрибут VAR употреблялся для привязки к типу данных метода через передачу скрытой ссылки на описатель этого типа данных. Различия в привязке методов к типам будут описаны отдельно. [↑] ==== 6. Выводы ==== Задание атрибутов параметрам функций позволяет более точно управлять приложением. Промышленное программирование требует особого контроля в вопросах обращения к структурам данных. Описанные атрибуты частично входят в вопросы метапрограммирования, уточняют принципы ООП в динамических системах. IN, OUT и VAR-параметры позволяют расширить классический процедурный стиль в разумных пределах, ровно столько, сколько это может требоваться на практике, и при этом, не усложнять семантику Компонентного Паскаля. [↑] [ ← Назад ] [ Вверх ↑ ] [ Далее → ]