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