Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курс лекций Языки программирования.doc
Скачиваний:
1
Добавлен:
01.04.2025
Размер:
1.42 Mб
Скачать

Процедурные абстракции

Традиционно к процедурным абстракциям мы относим подпрограммы и фукции. Вообще говоря, есть еще одно понятие, которое мы также рассмотрим, это - сопрограммы. Рассмотрение мы будем вести с двух сторон:

  • с точки зрения передачи управления;

  • с точки зрения передачи данных;

Передача управления

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

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

В современных ЯП точка входа - одна, это стало аксиомой для ЯП, начиная с 70х годов. Хотя, старые ЯП (например, Fortran) имели конструкции, которые позволяли «входить» в подпрограмму в различных точках.

Множественные точки выхода - допускаются, как уже было сказано выше. Для этого в современнях ЯП имеется, как правило, оператор RETURN (или аналоги), который завершает выполнение подпрограммы. Множественные точки выхода не противоречат принципу черного ящика (т.к. их всегда можно свести к одной точке).

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

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

Заметим, что схема с подпрограммами - несимметрична. То есть у нас есть главная программа и подпрограмма. Вызываем мы из разных точек, а управление попадает всегда в одну точку:

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

Фактически у нас попеременно выполняется то COR1, то COR2, но в отличии от подпрограмм, управление передается каждый раз не на точку входа COR1 или COR2, а на точку, где сопрограмма была прервана последний раз. И еще - при использовании подпрограмм мы говорим об операторах вызова и возврата, здесь же нельзя провести подобное разделение. Мы имеем оператор передачи управления. Обычно употребляют имена RESUME или TRANSFER.

Сопрограммы могут быть реализованы в языке С через setjump/longjump, нечто подобное присутствовало и в Модула-2, правда, не на базисном уровне, а на уровне библиотеки.

В Модула-2 существует функция TRANSFER( COR1, COR2), параметры COR1 и COR2 имеют тип ADDRESS (указатель «куда-то там», аналог void * в языке C). Зачем нужно два параметра? Очевидно, для того, чтобы запоминать, куда следует возвращаться, каково было состояние процесса в том месте, где мы его прервали. С точки зрения смысла COR1 и COR2 должны иметь тип некоторого контекста, в котором хрянятся регистры, счетчик команд и т.д. Но вместо того, чтобы описывать всю структуру на верхнем уровне, ее скрыли под тип ADDRESS. Чтобы передать управление обратно достаточно вызвать TRANSFER(COR2, COR1).

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

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

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