Как происходит отслеживание свободного экстента? |
Подпрограммы, функциональная абстракция, скрытие информации
8.9. Приложение: Доказательство неразрешимости проблемы остановки
Ранее было отмечено, что невозможно создать алгоритм ("эффективную процедуру"), который бы для любой программы определял, остановится ли она. Давайте докажем этот факт, предполагая, что, если бы такой алгоритм существовал, то мы могли бы написать его реализацию на Eiffel.
Предположим, что алгоритм существует и мы написали реализующую его функцию:
terminates (root_directory: STRING): BOOLEAN - Для программной системы, заданной аргументом root_directory, - если она есть, определить, завершится ли она? do ... Подходящий, очень умный алгоритм ... end
Аргумент root_directory задает имя каталога, в котором хранится "ECF" программы — описание системных установок, дающих доступ ко всем классам, спецификациям корневого класса и корневой процедуры создания. Для простоты будем полагать, что ECF — это файл, названный system.ecf, хранящийся в каталоге. Наша способность решить проблему остановки означает, что мы способны написать "Подходящий, очень умный алгоритм", так что terminates (r) будет возвращать True, если и только если такой файл задан аргументом r и выполнение соответствующей программы приводит к завершению.
Можно изменить соглашения, адаптируя доказательство к любому другому языку программирования. Вместо ECF аргумент мог быть просто именем файла, содержащего текст всех классов программной системы, с указанием корневой процедуры и класса. Что важно на самом деле - это то, что аргумент функции terminates должен позволять передать ей текст некоторой системы. Работа функции terminates состоит в определении, будет ли переданная ей система останавливаться.
До сих пор мы полагали, что проверяемой системе не нужен никакой вход во время ее работы. В более общей постановке можно задать и входные данные:
terminates_on_input (root_directory: STRING; input: STRING): BOOLEAN - Для программной системы, заданной аргументом root_directory, - если она есть, определить, завершится ли она на входе input? do … Подходящий, очень умный алгоритм… end
Будем рассматривать первую форму постановки задачи, но доказательство применимо и к форме со входными данными.
Доказательство простое. Если написан метод terminates, то тогда нетрудно написать и программу со следующей корневой процедурой:
paradox — Завершается, если и только если не завершается terminates. do from until not terminates ("C:\your_project") loop end end
Здесь C:\your_project — это произвольное имя каталога (папки) в стиле Windows. Фактически важно лишь то, что мы указываем здесь каталог, хранящий саму систему "paradox". Тогда вызов terminates решит, завершится ли эта система. Давайте рассмотрим, как будет выполняться процедура создания.
- Если функция terminates определит в результате анализа текста системы "paradox", что ее выполнение не завершается, то в этом случае условие выхода из цикла выполнится после первого выполнения тела цикла и система "paradox" тут же завершит свою работу. Пришли к противоречию с результатом, выданным "очень умным" алгоритмом terminates.
- Если функция terminates определит в результате анализа текста системы "paradox", что ее выполнение завершается, то в этом случае условие выхода из цикла никогда не будет выполняться и система "paradox" зациклится. Пришли опять-таки к противоречию с результатом, выданным "очень умным" алгоритмом terminates.
Это и доказывает, что невозможно написать функцию terminates, на вход которой можно было бы передать описание любого метода для определения его завершаемости.
Мы увидим в последующих лекциях более краткую версию доказательства, применяющую рекурсию. В одном из упражнений предстоит написать короткое доказательство, использующее агенты.
8.10. Дальнейшее чтение
David Parnas: A Technique for Software Specification with Examples, in Communications of the ACM, vol. 15, no. 5, 1972, p. 330-336, and On the Criteria to be Used in Decomposing Systems into Modules, ibid, vol. 15, no. 12, 1972, p. 1053-1058.
На русском языке: "Метод спецификации модулей ПО с примерами" в сб. "Данные в языках программирования" под ред. В. Агафонова, М., Мир. 1982 г.
Две классические статьи, в которых вводится понятие скрытия информации. До сих пор не утратили значения.
Ключевые концепции, изученные в этой лекции
- Методы обеспечивают функциональную абстракцию: способность именования возможно параметризованных алгоритмов.
- В подходе "сверху вниз" метод может выступать в роли "заглушки" — держателя места, для алгоритма, который будет детализирован позже в процессе проектирования. В подходе "снизу вверх" уже созданный метод может повторно использоваться в разных проектах.
- В ОО-контексте методы являются одним из двух видов характеристик класса (feature). Сами методы разделяются на две категории: функции, возвращающие результат, и процедуры, которые этого не делают.
- Методы могут иметь аргументы, которые позволяют вызывающему методу передать информацию, специфическую для каждого вызова.
- Метод имеет имя, сигнатуру, определяемую типами аргументов, результат, если он есть, контракт и тело, описывающее алгоритм.
- Имя, сигнатура и контракт определяют интерфейс метода, доступный авторам клиентских модулей.
- Скрытие информации является механизмом, позволяющим отделить интерфейс от реализации, что позволяет клиентам применять методы, основываясь только на информации, заключенной в интерфейсе.
- Скрытие информации облегчает разработку больших систем, повторное использование программных элементов и гладкую эволюцию системы.
Новый словарь
8-У. Упражнения
8-У.1. Словарь09
Дайте точные определения терминам словаря.
8-У.2. Концептуальная карта
Добавьте новые термины в концептуальную карту, созданную в предыдущих лекциях.