Это старая версия документа!
Компонентный Паскаль поддерживает процедурный стиль программирования. Более того, использование процедур совершенно необходимо. Как было показано на двух примерах ранее — невозможно заставить исполнить код модуля, кроме как обратиться к имени процедуры. Идея процедуры используется почти во всех парадигмах программирования: ООП, функциональный стиль, АОП… Пожалуй, единственный стиль, который не использует процедурный подход — макаронное программирование1). Наличие такой возможности во всех парадигмах только ещё раз подчёркивает её важность.
Процедура в КП (впрочем, как и в любом ЯП) — это маленькая программа, работающая в интересах всей программы, причём, обычно, когда процедура получает управление, основная программа ждёт результатов её работы2). Поэтому нет ничего удивительного в том, что оформление процедуры очень похоже на оформление модуля:
PROCEDURE Старт; BEGIN мЛог.String('Привет, мир!'); мЛог.Ln END Старт;
Это та самая процедура, которая уже встречалась в примере «Привет, мир!».
Процедура объявляется ключевым словом PROCEDURE
, после которого следует само имя процедуры, заканчивается объявление процедуры — точкой с запятой. Как было описано раньше, по соглашению принятому в КП — имена процедур начинаются с большой буквы.
Начинается любая процедура с ключевого слова BEGIN
, а заканчивается ключевым словом END
. Причём после END
обязательно указывается имя процедуры. Так компилятор может контролировать содержимое процедуры. После имени процедуры следует точка с запятой, которая говорит компилятору о том, что это ещё не конец модуля (только END
с точкой может быть указателем того, что модуль закончился).
Весь полезный код начинается после ключевого слова BEGIN
. Ключевое слово VAR
также может быть использовано за объявлением процедуры, в этой секции описываются переменные, которые могут быть использованы только в текущей процедуре, но не могут быть использованы во всём модуле. В отличии от модуля использовать ключевое слово IMPORT
в процедурах запрещается. Ключевое слово CONST
вполне употребимо, и компилятор не будет возражать.
Как было описано в одном из предыдущих разделов, после последней инструкции в теле процедуры — перед END
— точку с запятой ставить не нужно.
Параметром называется какая-либо переменная, которая передаётся в процедуру. Процедура, которая определена без параметров (например, Start
) называется «процедурой без параметров».
Такие процедуры встречаются не часто. И использование таких процедур хоть и возможно в КП, но не приветствуется. Как правило такие процедуры используют переменные, объявленные в других местах. Изменение этих переменных таким способом нарушает принцип разделения и сокрытия информации, что приводит к снижению надёжности программ.
Это основной вид процедур в КП. Для того, чтобы процедура приняла какие либо параметры, нужно их описать в объявлении процедуры:
В приведённой процедуре LogReal
используется формальный параметр r
. Тип этого параметра — REAL
. Далее, те параметры, которые процедура требует на входе, вместо формальные параметры (как официально принято) будем их называть входные параметры, или совсем коротко параметры3). В объявлениях процедур можно описывать несколько параметров, все они записываются в скобках подряд и разделяются точкой с запятой.
Вызов процедуры с параметрами можно выполнить передав процедуре фактические параметры (официальное название). Далее такие параметры будем называть передаваемые аргументы или совсем коротко аргументы4) Полный код программы с вызовом процедуры представлен ниже:
Hello03.odc
MODULE TestHello03; (* это третья программа на языке Компонентный Паскаль. Она выполняет кое-какие математические операции и показывает как использовать процедуры *) IMPORT Log; CONST c = 2; VAR i: INTEGER; i1: REAL; PROCEDURE LogReal (r: REAL); VAR BEGIN Log.Real(r); Log.Ln END LogReal; PROCEDURE Start*; VAR BEGIN i := 3; i1 := c / i; Log.String('Привет, мир!'); Log.Ln; LogReal(i1) END Start; BEGIN END TestHello03.
Этот вариант программы делает всё тоже самое, что и предыдущая, но с использованием дополнительной процедуры LogReal
описанной выше. Передаваемый аргумент i1
должен иметь тот же тип, что и требуемый параметр в объявлении процедуры. В противном случае, КП посчитает это ошибкой. Теперь вместо двух инструкций Log.Real(i1); Log.Ln
можно писать только одну, что приводит к сокращению набираемого кода. В этом примере заключается одна из ключевых идей процедурного стиля. Но обратите внимание, что для вызова процедуры компьютеру требуется выполнить ряд дополнительный служебных действий, и при возврате из процедуры также выполняются некоторые действия, что приводит к дополнительным небольшим затратам времени. Поэтому, вызов процедуры должен быть оправдан. Само тело процедуры не должно состоять из одной инструкции, так как в этом нет никакого смысла.
Ещё один момент на который необходимо обратить внимание — это порядок размещения процедур. Если процедуру LogReal
разместить позже процедуры Start
компилятор КП не сможет понять, что за процедуру вызывает инструкция LogReal(i1)
. Компиляция завершится ошибкой. Поэтому, объявление процедур должно быть упреждающим.
Процедура может возвращать какое-либо значение в случае необходимости. Для этого существует специальное ключевое слово RETURN
. После него размещается переменная, значение которой должно быть возвращено. Вместо переменной можно написать какое-либо выражение (например, вызов другой процедуры)5). Давайте модифицируем процедуру LogReal
, чтобы она это могла делать:
PROCEDURE MathLogReal (p1, p2: INTEGER): REAL; VAR r: REAL; BEGIN r := p1 / p2; Log.Real(r); Log.Ln; RETURN r END MathLogReal;
Теперь процедура LogReal
не только выводит значение переменной типа REAL
, но и может рассчитать его. Поэтому, было изменено название процедуры на MathLogReal
. Обратите внимание, как определены два входных параметра типа INTEGER
— подряд через запятую. За списком параметров указан тип возвращаемого значения. Также впервые была использована секция процедуры VAR
, в которой определена переменная r
типа REAL
, значение которой, рассчитывается внутри процедуры, и в конечном итоге возвращается. Если ключевое слово RETURN
разместить перед вычислениями, то сами вычисления не будут выполнены, а в процедуру Start
будет возвращено непонятно что (мусор).
Полный код модифицированной программы приведён ниже:
Hello04.odc
MODULE TestHello04; (* это четвёртая программа на языке Компонентный Паскаль. Она выполняет кое-какие математические операции и показывает как использовать процедуры, которые возвращают значение *) IMPORT Log, Math; CONST c = 2; VAR i: INTEGER; i1: REAL; PROCEDURE MathLogReal (p1, p2: INTEGER): REAL; VAR r: REAL; BEGIN r := p1 / p2; Log.Real(r); Log.Ln; RETURN r END MathLogReal; PROCEDURE Start*; VAR BEGIN Log.String('Привет, мир!'); Log.Ln; i := 3; i1 := MathLogReal(c, i) END Start; BEGIN END TestHello04.
Как видно из текста модуля, процедура Start
стала существенно короче. Кроме того, константа с
успешно передаётся в процедуру. Это говорит о том, что компилятор КП автоматически присвоил ей тип INTEGER
(мы тип этой константы не описали). Кроме того, ни модуль, ни процедура Start
не подозревают о наличии переменной r
внутри процедуры MathLogReal
. А значит ни одна процедура модуля (и сам модуль) не могут испортить её значение. Так достигается сокрытие информации.
Самые внимательные читатели уже обратили внимание на то, что за именем процедуры Start
стоит символ (*). Этот символ как раз и указывает компилятору сделать экспорт процедуры из модуля. Попробуйте уберите звёздочку и скомпилируйте — вы не сможете вызвать процедуру Start
. После экспорта, указанная процедура может быть вызвана извне модуля. Именно поэтому её можно запустить на выполнение через КОММАНДЕР
. Тема экспорта очень важна, и в этом разделе получила лишь минимальное освещение, о других особенностях экспорта речь ещё пойдёт дальше.
В этой части учебника были рассмотрены в первом приближении очень важные положения КП процедурного стиля:
Этих знаний должно хватить для написания программ в хорошем процедурном стиле. Описанные здесь особенности лишь часть того, что можно сделать с процедурами, но так как полное освещение потребует более глубоких знаний в этой области, пока остановимся на этом.