Инструменты пользователя

Инструменты сайта


bb:redbook:107

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
bb:redbook:107 [2016/04/14 12:09]
prospero78 [7. Экспорт процедуры]
bb:redbook:107 [2017/12/26 07:51]
иван_денисов удалено
Строка 3: Строка 3:
 ==== 1. Процедуры ==== ==== 1. Процедуры ====
 **Компонентный Паскаль** поддерживает //процедурный стиль// программирования. Более того, использование процедур //совершенно необходимо//. Как было показано на двух примерах ранее — невозможно заставить исполнить код модуля, кроме как обратиться к имени процедуры. Идея процедуры используется почти во всех парадигмах программирования: **ООП, функциональный стиль, АОП**... Пожалуй, единственный стиль, который не использует процедурный подход — //макаронное программирование//((это были ужасные времена. Писать в таком стиле это просто вынос мозга. Подробнее почитать можно в [[https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B0%D0%B3%D0%B5%D1%82%D1%82%D0%B8-%D0%BA%D0%BE%D0%B4|Википедии]])). Наличие такой возможности во всех парадигмах только ещё раз подчёркивает её важность. **Компонентный Паскаль** поддерживает //процедурный стиль// программирования. Более того, использование процедур //совершенно необходимо//. Как было показано на двух примерах ранее — невозможно заставить исполнить код модуля, кроме как обратиться к имени процедуры. Идея процедуры используется почти во всех парадигмах программирования: **ООП, функциональный стиль, АОП**... Пожалуй, единственный стиль, который не использует процедурный подход — //макаронное программирование//((это были ужасные времена. Писать в таком стиле это просто вынос мозга. Подробнее почитать можно в [[https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B0%D0%B3%D0%B5%D1%82%D1%82%D0%B8-%D0%BA%D0%BE%D0%B4|Википедии]])). Наличие такой возможности во всех парадигмах только ещё раз подчёркивает её важность.
 +
 ==== 2. Оформление процедуры ==== ==== 2. Оформление процедуры ====
 Процедура в **КП** (впрочем, как и в любом **ЯП**) — это маленькая программа, работающая в интересах всей программы, причём, обычно, когда процедура получает управление, основная программа ждёт результатов её работы((Основная программа на современных компьютерах может не ждать, пока подпрограмма выполняется (если это требует много времени). Если такая подпрограмма выполняется в потоке главной программы она называется //сопрограмма// или //легковесный поток// (при этом может останавливать выполнение основной программы). Если в состав компьютера входит множество вычислительных узлов, то такая подпрограмма называется //процесс//.Подробнее смотрите в [[https://ru.wikipedia.org/wiki/Green_threads|Википедии]])). Поэтому нет ничего удивительного в том, что оформление процедуры очень похоже на оформление модуля: Процедура в **КП** (впрочем, как и в любом **ЯП**) — это маленькая программа, работающая в интересах всей программы, причём, обычно, когда процедура получает управление, основная программа ждёт результатов её работы((Основная программа на современных компьютерах может не ждать, пока подпрограмма выполняется (если это требует много времени). Если такая подпрограмма выполняется в потоке главной программы она называется //сопрограмма// или //легковесный поток// (при этом может останавливать выполнение основной программы). Если в состав компьютера входит множество вычислительных узлов, то такая подпрограмма называется //процесс//.Подробнее смотрите в [[https://ru.wikipedia.org/wiki/Green_threads|Википедии]])). Поэтому нет ничего удивительного в том, что оформление процедуры очень похоже на оформление модуля:
 <code oberon2> <code oberon2>
-VAR +PROCEDURE Старт;
 BEGIN BEGIN
- Log.String('Привет, мир!'); + мЛог.String('Привет, мир!'); 
- Log.Ln + мЛог.Ln 
-END Start;+END Старт;
 </code> </code>
      
  
-Это та самая процедура, которая уже встречалась в примере "HelloWorld!".+Это та самая процедура, которая уже встречалась в примере "Приветмир!".
  
 Процедура объявляется ключевым словом ''PROCEDURE'', после которого следует само имя процедуры, заканчивается объявление процедуры — точкой с запятой. Как было описано раньше, по соглашению принятому в **КП** — имена процедур начинаются с большой буквы. Процедура объявляется ключевым словом ''PROCEDURE'', после которого следует само имя процедуры, заканчивается объявление процедуры — точкой с запятой. Как было описано раньше, по соглашению принятому в **КП** — имена процедур начинаются с большой буквы.
Строка 25: Строка 25:
 Как было описано в одном из предыдущих разделов, после последней инструкции в теле процедуры — перед ''END'' — точку с запятой ставить не нужно. Как было описано в одном из предыдущих разделов, после последней инструкции в теле процедуры — перед ''END'' — точку с запятой ставить не нужно.
 ==== 3. Процедура без параметров ==== ==== 3. Процедура без параметров ====
-Параметром называется какая-либо переменная, которая передаётся в процедуру. Процедура, которая определена без параметров (например, ''Start'') называется "процедурой без параметров".+Параметром называется какая-либо переменная, которая передаётся в процедуру. Процедура, которая определена без параметров (например, ''Старт'') называется "процедурой без параметров".
  
 Такие процедуры встречаются не часто. И использование таких процедур хоть и возможно в **КП**, но не приветствуется. Как правило такие процедуры используют переменные, объявленные //в других местах//. Изменение этих переменных таким способом //нарушает// принцип //разделения и сокрытия информации//, что приводит к //снижению// надёжности программ.  Такие процедуры встречаются не часто. И использование таких процедур хоть и возможно в **КП**, но не приветствуется. Как правило такие процедуры используют переменные, объявленные //в других местах//. Изменение этих переменных таким способом //нарушает// принцип //разделения и сокрытия информации//, что приводит к //снижению// надёжности программ.
Строка 38: Строка 38:
  
 <code oberon2> <code oberon2>
-MODULE TestHello03;+MODULE КнигаПривет3;
  (* это третья программа на языке  (* это третья программа на языке
  Компонентный Паскаль. Она выполняет  Компонентный Паскаль. Она выполняет
Строка 44: Строка 44:
  показывает как использовать процедуры *)  показывает как использовать процедуры *)
  
- IMPORT Log;+ IMPORT мЛог := Log; 
  CONST  CONST
- = 2;+ _конст = 2; 
  VAR  VAR
- i: INTEGER; + цПерем: INTEGER; 
- i1: REAL;+ вПерем: REAL;
  
- PROCEDURE LogReal (r: REAL);+ PROCEDURE Вещ_Печать (пвПерем: REAL);
  VAR  VAR
  BEGIN  BEGIN
- Log.Real(r); + мЛог.Real(пвПерем); 
- Log.Ln + мЛог.Ln 
- END LogReal;+ END Вещ_Печать;
  
- PROCEDURE Start*;+ PROCEDURE Старт*;
  VAR  VAR
  BEGIN  BEGIN
- := 3; + цПерем := 3; 
- i1 := i+ вПерем := _конст цПерем
- Log.String('Привет, мир!'); Log.Ln; + мЛог.String('Привет, мир!'); мЛог.Ln; 
- LogReal(i1+ Вещ_Печать(вПерем
- END Start;+ END Старт;
  
 BEGIN BEGIN
-END TestHello03.+END КнигаПривет3.
 </code>  </code> 
   
-Этот вариант программы делает всё тоже самое, что и предыдущая, но с использованием дополнительной процедуры ''LogReal'' описанной выше. Передаваемый аргумент ''i1'' должен иметь тот же тип, что и требуемый параметр в объявлении процедуры. В противном случае, **КП** посчитает это ошибкой. Теперь вместо двух инструкций ''Log.Real(i1); Log.Ln'' можно писать только одну, что приводит к сокращению набираемого кода. В этом примере заключается одна из ключевых идей процедурного стиля. Но обратите внимание, что для вызова процедуры компьютеру требуется выполнить ряд дополнительный служебных действий, и при возврате из процедуры также выполняются некоторые действия, что приводит к дополнительным небольшим затратам времени. Поэтому, //вызов процедуры должен быть оправдан//. Само тело процедуры не должно состоять из одной инструкции, так как в этом //нет никакого смысла//.+Этот вариант программы делает всё тоже самое, что и предыдущая, но с использованием дополнительной процедуры ''Вещ_ Печать'' описанной выше. Передаваемый аргумент ''вПерем'' должен иметь тот же тип, что и требуемый параметр в объявлении процедуры. В противном случае, **КП** посчитает это ошибкой. Теперь вместо двух инструкций ''мЛог.Real(вПерем); Log.Ln'' можно писать только одну, что приводит к сокращению набираемого кода. В этом примере заключается одна из ключевых идей процедурного стиля. Но обратите внимание, что для вызова процедуры компьютеру требуется выполнить ряд дополнительный служебных действий, и при возврате из процедуры также выполняются некоторые действия, что приводит к дополнительным небольшим затратам времени. Поэтому, //вызов процедуры должен быть оправдан//. Само тело процедуры не должно состоять из одной инструкции, так как в этом //нет никакого смысла//.
  
-Ещё один момент на который необходимо обратить внимание — это порядок размещения процедур. Если процедуру ''LogReal'' разместить позже процедуры ''Start'' компилятор **КП** не сможет понять, что за процедуру вызывает инструкция ''LogReal(i1)''. Компиляция завершится ошибкой. Поэтому, объявление процедур должно быть упреждающим.+Ещё один момент на который необходимо обратить внимание — это порядок размещения процедур. Если процедуру ''Вещ Печать'' разместить позже процедуры ''Старт'' компилятор **КП** не сможет понять, что за процедуру вызывает инструкция ''Вещ Печать(вПерем)''. Компиляция завершится ошибкой. Поэтому, объявление процедур должно быть упреждающим.
   
 ==== 6. Возврат значения из процедуры ==== ==== 6. Возврат значения из процедуры ====
-Процедура может возвращать какое-либо значение в случае необходимости. Для этого существует специальное ключевое слово ''RETURN''. После него размещается переменная, значение которой должно быть возвращено. Вместо переменной можно написать какое-либо выражение (например, вызов другой процедуры)[4]. Давайте модифицируем процедуру ''LogReal'', чтобы она это могла делать:+Процедура может возвращать какое-либо значение в случае необходимости. Для этого существует специальное ключевое слово ''RETURN''. После него размещается переменная, значение которой должно быть возвращено. Вместо переменной можно написать какое-либо выражение (например, вызов другой процедуры)((Вообще, в других языках программирования (например, [[https://ru.wikipedia.org/wiki/Visual_Basic|Visual Basic]]) процедуры возвращающие результат называются функции. И для определения функций предусмотрено отдельное ключевое слово. Но с точки зрения современного подхода это является неоправданным излишеством (функции из текста программы вызываются также, как и процедуры, отличить можно только по факту возврата результата).)). Давайте модифицируем процедуру ''LogReal'', чтобы она это могла делать:
  
 <code oberon2> <code oberon2>
-PROCEDURE MathLogReal (p1p2: INTEGER): REAL;+PROCEDURE Вещ_Вычисл(пцЗнач1пцЗнач2: INTEGER): REAL;
  VAR  VAR
- r: REAL;+ вРезульт: REAL;
 BEGIN BEGIN
- := p1 p2+ вРезульт := пцЗнач1 пцЗнач2
- Log.Real(r); + мЛог.Real(вРезульт); 
- Log.Ln; + мЛог.Ln; 
- RETURN r + RETURN вРезульт 
-END MathLogReal;+END Вещ_Вычисл;
 </code> </code>
  
-Теперь процедура ''LogReal'' не только выводит значение переменной типа ''REAL'', но и может рассчитать его. Поэтому, было изменено название процедуры на ''MathLogReal''. Обратите внимание, как определены два входных параметра типа ''INTEGER'' — подряд через запятую. За списком параметров указан тип возвращаемого значения. Также впервые была использована секция процедуры ''VAR'', в которой определена переменная ''r'' типа ''REAL'', значение которой, рассчитывается внутри процедуры, и в конечном итоге возвращается. Если ключевое слово ''RETURN'' разместить перед вычислениями, то сами вычисления не будут выполнены, а в процедуру ''Start'' будет возвращено непонятно что (//мусор//).+Теперь процедура ''Вещ Печать'' не только выводит значение переменной типа ''REAL'', но и может рассчитать его. Поэтому, было изменено название процедуры на ''Вещ Вычисл''. Обратите внимание, как определены два входных параметра типа ''INTEGER'' — подряд через запятую. За списком параметров указан тип возвращаемого значения. Также впервые была использована секция процедуры ''VAR'', в которой определена переменная ''вРезульт'' типа ''REAL'', значение которой, рассчитывается внутри процедуры, и в конечном итоге возвращается. Если ключевое слово ''RETURN'' разместить перед вычислениями, то сами вычисления не будут выполнены, а в процедуру ''Старт'' будет возвращено непонятно что (//мусор//).
   
 Полный код модифицированной программы приведён ниже: Полный код модифицированной программы приведён ниже:
Строка 96: Строка 98:
 Hello04.odc Hello04.odc
 <code oberon2> <code oberon2>
-MODULE TestHello04;+MODULE КнигаПривет4;
  (* это четвёртая программа на языке  (* это четвёртая программа на языке
  Компонентный Паскаль. Она выполняет  Компонентный Паскаль. Она выполняет
Строка 103: Строка 105:
  которые возвращают значение *)  которые возвращают значение *)
  
- IMPORT Log, Math;+ IMPORT мЛог := Log, 
 + Math; 
 +
  CONST  CONST
- = 2;+ _конст = 2; 
 +
  VAR  VAR
- i: INTEGER; + цПерем: INTEGER; 
- i1: REAL;+ вПерем: REAL;
  
- PROCEDURE MathLogReal (p1p2: INTEGER): REAL;+ PROCEDURE Вещ_Вычисл (пцЗнач1пцЗнач2: INTEGER): REAL;
  VAR  VAR
- r: REAL;+ вРезульт: REAL;
  BEGIN  BEGIN
- := p1 p2+ вРезульт := пцЗнач1 пцЗнач2
- Log.Real(r); + мЛог.Real(вРезульт); 
- Log.Ln; + мЛог.Ln; 
- RETURN r + RETURN вРезульт 
- END MathLogReal;+ END Вещ_Вычисл;
  
- PROCEDURE Start*;+ PROCEDURE Старт*;
  VAR  VAR
  BEGIN  BEGIN
- Log.String('Привет, мир!'); Log.Ln; + мЛог.String('Привет, мир!'); мЛог.Ln; 
- := 3; + цПерем := 3; 
- i1 := MathLogReal(ci+ вПерем := Вещ_Вычисл(_констцПерем
- END Start;+ END Старт;
 BEGIN BEGIN
-END TestHello04.+END КнигаПривет4.
 </code> </code>
-Как видно из текста модуля, процедура ''Start'' стала существенно короче. Кроме того, константа ''с'' успешно передаётся в процедуру. Это говорит о том, что компилятор **КП** автоматически присвоил ей тип ''INTEGER'' (мы тип этой константы не описали). Кроме того, ни модуль, ни процедура ''Start'' не подозревают о наличии переменной ''r'' внутри процедуры ''MathLogReal''. А значит ни одна процедура модуля (и сам модуль) не могут испортить её значение. Так достигается сокрытие информации.+Как видно из текста модуля, процедура ''Старт'' стала существенно короче. Кроме того, константа ''_конст'' успешно передаётся в процедуру. Это говорит о том, что компилятор **КП** автоматически присвоил ей тип ''INTEGER'' (мы тип этой константы не описали). Кроме того, ни модуль, ни процедура ''Старт'' не подозревают о наличии переменной ''вРезульт'' внутри процедуры ''Вещ Вычисл''. А значит ни одна процедура модуля (и сам модуль) не могут испортить её значение. Так достигается сокрытие информации.
 ==== 7. Экспорт процедуры ==== ==== 7. Экспорт процедуры ====
-Самые внимательные читатели уже обратили внимание на то, что за именем процедуры ''Start*'' стоит символ (*). Этот символ как раз и указывает компилятору сделать //экспорт// процедуры из модуля. Попробуйте уберите звёздочку и скомпилируйте — вы не сможете вызвать процедуру ''Start''. После экспорта, указанная процедура может быть вызвана извне модуля. Именно поэтому её можно запустить на выполнение через ''КОММАНДЕР''. Тема экспорта //очень важна//, и в этом разделе получила лишь минимальное освещение, о других особенностях экспорта речь ещё пойдёт дальше.+Самые внимательные читатели уже обратили внимание на то, что за именем процедуры ''Старт'' стоит символ //звёздочка//. Этот символ как раз и указывает компилятору сделать //экспорт// процедуры из модуля. Попробуйте уберите звёздочку и скомпилируйте — вы не сможете вызвать процедуру ''Старт'' . После экспорта, указанная процедура может быть вызвана извне модуля. Именно поэтому её можно запустить на выполнение через ''КОММАНДЕР''. Тема экспорта //очень важна//, и в этом разделе получила лишь минимальное освещение, о других особенностях экспорта речь ещё пойдёт дальше.
 ==== 8. Заключение ==== ==== 8. Заключение ====
-В этой части учебника были рассмотрены в первом приближении очень важные положения КП процедурного стиля:+В этой части учебника были рассмотрены в первом приближении очень важные положения **КП** процедурного стиля:
   - Как объявить процедуру   - Как объявить процедуру
   - Как объявить входные параметры процедуры   - Как объявить входные параметры процедуры
Строка 141: Строка 146:
   - Как сделать процедуру доступной для исполнения извне модуля   - Как сделать процедуру доступной для исполнения извне модуля
   
-Этих знаний должно хватить для написания программ в хорошем процедурном стиле. Описанные здесь особенности лишь часть того, что можно сделать с процедурами, но так как полное освещение потребует более глубоких знаний в этой области, пока остановимся на этом. [↑] +Этих знаний должно хватить для написания программ в //хорошем// процедурном стиле. Описанные здесь особенности лишь //часть// того, что можно сделать с процедурами, но так как полное освещение потребует более глубоких знаний в этой области, пока остановимся на этом.
- +
-———————————————————- +
-==== 9. Примечания ==== +
- +
-[↑] Неофициальные названия "формальных параметров" и "фактических параметров" вводятся целенаправленно. Различать "параметры" и "аргументы" на слух значительно легче. +
- +
-[↑] Вообще, в других языках программирования (например, Visual Basic) процедуры возвращающие результат называются функции. И для определения функций предусмотрено отдельное ключевое слово. Но с точки зрения современного подхода это является неоправданным излишеством (функции из текста программы вызываются также, как и процедуры, отличить можно только по факту возврата результата).+
  
-[ ← Назад  ] [ Вверх ↑ ] [ Далее → ]