
- •Часть I. Традиционные Языки Программирования
- •Глава 1. Управляющие структуры. Процедурные абстракции.
- •Базисные свойства языков программирования
- •Процедурные абстракции
- •Передача управления
- •Передача данных
- •Глава II. Основные понятия и проблемы, связанные с типами данных
- •Глава III. Базисные типы данных
- •3.1 Простые типы данных
- •3.1.2. Другие базисные типы данных.
- •Определение новых типов данных
- •Конструкторы.
- •Конструктор умолчания.
- •Конструктор копирования.
- •Конструктор преобразования.
- •Операторы преобразования.
- •Деструкторы
- •Глава 5. Инкапсуляция. Абстрактные типы данных (атд).
- •Модула–2.
- •Оберон.
- •Инициализация статических членов в Java (отступление)
- •Глава 5. Инкапсуляция. Абстрактные типы данных (атд) (продолжение).
- •Язык Java.
- •Глава 6. Раздельная трансляция.
- •Раздельная независимая трансляция
- •Именование
- •Include-файлы
- •Раздельная зависимая трансляция
- •Глава 7. Статическая параметризация.
- •Язык Ада.
- •Глава 7. Исключительные ситуации в языках программирования.
- •1. Объявление исключений.
- •2. Определение исключения.
- •3. Возникновение.
- •4. Распространение и обработка.
- •Часть II. Объектно-ориентированные яп.
- •Глава I. Наследование в яп.
- •1. Каждый объект данных имеет ровно один тип.
- •2. Типы эквивалентны тогда и только тогда, когда их имена совпадают.
- •3. Каждый тип данных характеризуется набором данных и множеством операций.
- •4. Различные типы не совместимы по присваиванию и передаче параметров.
- •Множественное наследование.
- •Глава 2. Динамическое связывание методов.
- •Динамическое связывание методов
- •Снятие механизма виртуального вызова
- •Абстрактные методы. Абстрактные классы.
- •Динамическая идентификация типа.
- •3. Полиморфизм.
Процедурные абстракции
Традиционно к процедурным абстракциям мы относим подпрограммы и фукции. Вообще говоря, есть еще одно понятие, которое мы также рассмотрим, это - сопрограммы. Рассмотрение мы будем вести с двух сторон:
с точки зрения передачи управления;
с точки зрения передачи данных;
Передача управления
У каждой процедурной абстракции есть понятие точки входа и точки выхода. Когда мы говорили о программировании, то мы дошли до того, что абстракция должна представлять из себя черный ящик с одним входом и одним выходом.
Конечно, реализация такой абстракции немного отличается - например, выход из процедуры может быть не один (выход при возникновении ошибочной ситуации). Но тем не менее, общая схема такова.
В современных ЯП точка входа - одна, это стало аксиомой для ЯП, начиная с 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).
Сейчас разговоров о сопрограммах стало значительно меньше, чем раньше. Почему? Во-первых, мы уже видели на примере двух ЯП, что понятие сопрограммы реализуется, как расширение языка на основе базисной части. Во-вторых, заметим, что механизм сопрограмм похож на квазипараллельное выполнение, конечно, с большими упрощениями, особенно в части синхронизации, но тем не менее, в целом, схема та же самая. В результате сопрограммы хорошо обобщаются методами параллельного выполнения, и нет смысла включать их в базис языка. Кроме того, программирование современных событийно-ориентированных систем очень похоже на передачу управления в сопрограммах, когда процессы постоянно прерываются для выполнения других процессов.
Таким образом, мы увидели, как методом проб и ошибок, рационализацией было упрощено понятие подпрограмм. Современные языки не реализуют сопрограммы на базисном уровне, так как это всегда можно сделать некоторыми расширениями.
На этом мы закончим обсуждение вопроса о передаче управления и обсудим каким образом происходит передача данных в момент вызова подпрограмм.