
- •Бертран Мейер Основы объектно-ориентированного программирования Аннотация
- •Лекция 1. Качество по
- •Внешние и внутренние факторы
- •Обзор внешних факторов
- •Корректность (Correctness)
- •Устойчивость (Robustness)
- •Расширяемость (Extendibility)
- •Повторное использование (Reusability)
- •Совместимость (Compatibility)
- •Эффективность (Efficiency)
- •Переносимость (Portability)
- •Простота использования (Easy of Use)
- •Функциональность (Functionality)
- •Своевременность (Timeliness)
- •Другие качества
- •О документации
- •Компромиссы
- •Ключевые вопросы
- •О программном сопровождении
- •Ключевые концепции
- •Лекция 2. Критерии объектной ориентации
- •О критериях
- •До какой степени мы должны быть догматичными?
- •Категории
- •Метод и язык
- •Бесшовность (seamlessness)
- •Утверждения (Assertions)
- •Классы как модули
- •Классы как типы
- •Вычисления, основанные на компонентах
- •Скрытие информации (information hiding)
- •Обработка исключений (Exception handling)
- •Статическая типизация (static typing)
- •Универсальность (genericity)
- •Единичное наследование (single inheritance)
- •Множественное наследование (Multiple inheritance)
- •Дублируемое наследование (Repeated inheritance)
- •Ограниченная универсальность (Constrained genericity)
- •Переопределение (redefinition)
- •Полиморфизм
- •Динамическое связывание
- •Выяснение типа объекта в период выполнения
- •Отложенные (deferred) свойства и классы
- •Управление памятью (memory management) и сборка мусора (garbage collection)
- •Реализация и среда
- •Автоматическое обновление (automatic update)
- •Быстрое обновление (fast update)
- •Живучесть (persistence)
- •Документация
- •Быстрый просмотр (browsing)
- •Библиотеки
- •Базовые библиотеки
- •Графика и пользовательские интерфейсы
- •Механизмы эволюции библиотек
- •Механизмы индексации в библиотеках
- •Продолжение просмотра
- •Библиографические ссылки и объектные ресурсы
- •Лекция 3. Модульность
- •Пять критериев
- •Декомпозиция
- •Модульная Композиция
- •Модульная Понятность
- •Модульная Непрерывность
- •Модульная Защищенность
- •Пять правил
- •Прямое отображение
- •Минимум интерфейсов
- •Слабая связность интерфейсов
- •Явные интерфейсы
- •Скрытие информации
- •Пять принципов
- •Лингвистические Модульные Единицы
- •Самодокументирование
- •Унифицированный Доступ
- •Открыт-Закрыт
- •Единственный Выбор
- •Ключевые концепции
- •Библиографические замечания
- •У3.5 Модульность существующих систем
- •У3.6 Управление конфигурацией и наследование
- •Лекция 4. Подходы к повторному использованию
- •Цели повторного использования
- •Ожидаемые преимущества
- •Потребители и производители повторно используемых программ
- •Что следует повторно использовать?
- •Повторное использование персонала
- •Повторное использование проектов и спецификаций
- •Образцы проектов (design patterns)
- •Повторное использование исходного текста
- •Повторное использование абстрактных модулей
- •Повторяемость при разработке по
- •Нетехнические препятствия
- •Синдром nih
- •Фирмы по разработке по и их стратегии
- •Организация доступа к компонентам
- •Несколько слов об индексировании компонентов
- •Форматы для распространения повторно используемых компонентов
- •Техническая проблема
- •Изменения и постоянство
- •Повторно использовать или переделать? (The reuse-redo dilemma)
- •Пять требований к модульным структурам
- •Изменчивость Типов (Type Variation)
- •Группирование Подпрограмм (Routine Grouping)
- •Изменчивость Реализаций (Implementation Variation)
- •Независимость Представлений
- •Факторизация Общего Поведения
- •Традиционные модульные структуры
- •Подпрограммы
- •Пакеты: оценка
- •Перегрузка и универсальность
- •Синтаксическая перегрузка
- •Семантическая перегрузка (предварительное представление)
- •Универсальность (genericity)
- •Основные методы модульности: оценка
- •Ключевые концепции
- •Библиографические замечания
- •Лекция 5. К объектной технологии
- •Ингредиенты вычисления
- •Базисный треугольник
- •Функциональная декомпозиция
- •Непрерывность
- •Проектирование сверху вниз
- •Не только одна главная функция
- •Обнаружение вершины
- •Функции и эволюция
- •Интерфейсы и проектирование по
- •Преждевременное упорядочение
- •Упорядочивание и оо-разработка
- •Возможность повторного использования
- •Производство и описание
- •Проектирование сверху вниз: общая оценка
- •Декомпозиция, основанная на объектах
- •Расширяемость
- •Возможность повторного использования
- •Совместимость
- •Объектно-ориентированное конструирование по
- •Вопросы
- •Выявление типов объектов
- •Описания типов и объектов
- •Описание отношений и структурирование по
- •Ключевые концепции
- •Библиографические замечания
- •Лекция 6. Абстрактные типы данных (атд)
- •Критерии
- •Различные реализации
- •Представления стеков
- •Опасность излишней спецификации
- •Какова длина второго имени?
- •К абстрактному взгляду на объекты
- •Использование операций
- •Политика невмешательства в обществе модулей
- •Согласованность имен
- •Можно ли обойтись без абстракций?
- •Формализация спецификаций
- •Специфицирование типов
- •Универсализация (Genericity)
- •Перечисление функций
- •Категории функций
- •Раздел аксиомы
- •Две или три вещи, которые мы знаем о стеках
- •Частичные функции
- •Предусловия
- •Полная спецификация
- •Ничего кроме правды
- •От абстрактных типов данных к классам
- •Как создавать эффективный класс
- •Роль отложенных классов
- •Абстрактные типы данных и скрытие информации
- •Переход к более императивной точке зрения
- •Назад к тому, с чего начали?
- •Конструирование объектно-ориентированного по
- •За пределами программ
- •Дополнительные темы
- •Еще раз о неявности
- •Соотношение спецификации и проектирования
- •Соотношение классов и записей
- •Альтернативы частичным функциям
- •Полна ли моя спецификация?
- •Item (new) - если это кажется странным, то см. Комментарии ниже.
- •Доказательство достаточной полноты
- •Ключевые концепции
- •Библиографические замечания
- •Упражнения у6.1 Точки
- •У6.2 Боксеры
- •Классы, а не объекты - предмет обсуждения
- •Устранение традиционной путаницы
- •Роль классов
- •Модули и типы
- •Класс как модуль и как тип
- •Унифицированная система типов
- •Простой класс
- •Компоненты
- •Атрибуты и подпрограммы
- •Унифицированный доступ
- •Класс point
- •Основные соглашения
- •Распознавание вида компонент
- •Тело подпрограммы и комментарии к заголовку
- •Предложение indexing
- •Обозначение результата функции
- •Правила стиля
- •Наследование функциональных возможностей общего характера
- •Объектно-ориентированный стиль вычислений
- •Текущий экземпляр
- •Клиенты и поставщики
- •Вызов компонента
- •Принцип единственности цели
- •Слияние понятий модуль и тип
- •Роль объекта Current
- •Квалифицированные и неквалифицированные вызовы
- •Компоненты-операции
- •Селективный экспорт и скрытие информации
- •Неограниченный доступ
- •Ограничение доступа клиентам
- •Стиль объявления скрытых компонент
- •"Внутренний" экспорт
- •Собираем все вместе
- •Общая относительность
- •Большой Взрыв
- •Системы
- •Программа main отсутствует
- •Компоновка системы
- •Классическое "Hello"
- •Структура и порядок: программист в роли поджигателя
- •Обсуждение
- •Форма объявлений
- •Атрибуты или функции?
- •Экспорт атрибутов
- •Доступ клиентов к атрибутам
- •Оптимизация вызовов
- •Архитектурная роль селективного экспорта
- •Импорт листингов
- •Присваивание функции результата
- •Дополнение: точное определение сущности
- •Ключевые концепции
- •Библиографические замечания
- •Объекты
- •Что такое объект?
- •Базовая форма
- •Простые поля
- •Простое представление книги - класс book
- •Писатели
- •Идентичность объектов
- •Объявление ссылок
- •Ссылка на себя
- •Взгляд на структуру объектов периода выполнения
- •Объекты как средство моделирования
- •Четыре мира программной разработки
- •Реальность: "седьмая вода на киселе"
- •Работа с объектами и ссылками
- •Динамическое создание и повторное связывание
- •Инструкция создания
- •Общая картина
- •Для чего необходимо явное создание объектов?
- •Процедуры создания
- •Перекрытие инициализации по умолчанию
- •Статус экспорта процедур создания
- •Правила, применимые к процедурам создания
- •Процедуры создания и перегрузка
- •Еще о ссылках
- •Состояния ссылок
- •Вызовы и пустые ссылки
- •Операции над ссылками
- •Присоединение ссылки к объекту
- •Сравнение ссылок
- •Значение void
- •Клонирование и сравнение объектов
- •Копирование объектов
- •Глубокое клонирование и сравнение
- •Глубокое хранилище: первый взгляд на сохраняемость
- •Составные объекты и развернутые типы
- •Ссылок не достаточно
- •Развернутые типы
- •Роль развернутых типов
- •Агрегирование
- •Свойства развернутых типов
- •Недопустимость ссылок на подобъекты
- •Присоединение: две семантики - ссылок и значений
- •Присоединение
- •Присоединение: ссылочное и копии
- •Гибридное присоединение
- •Проверка эквивалентности
- •Работа со ссылками: преимущества и опасности
- •Динамические псевдонимы
- •Семантика использования псевдонимов
- •Выработка соглашений для динамических псевдонимов
- •Псевдонимы в по и за его пределами
- •Инкапсуляция действий со ссылками
- •Обсуждение
- •Графические соглашения
- •Ссылки и простые значения
- •Форма операций клонирования и эквивалентности
- •Статус универсальных операций
- •Ключевые концепции
- •Библиографические замечания
- •Упражнения у8.1 Книги и авторы
- •У8.2 Личности
- •У8.3 Проектирование нотации
- •Лекция 9. Управление памятью
- •Что происходит с объектами
- •Создание объектов
- •Использование динамического режима
- •Повторное использование памяти в трех режимах
- •Отсоединение
- •Недостижимые объекты
- •Достижимые объекты в классическом подходе
- •Достижимые объекты в оо-модели
- •Проблема управления памятью в оо-модели
- •Три ответа
- •Несерьезный подход (тривиальный)
- •Может ли быть оправдан несерьезный подход?
- •Надо ли заботиться о памяти?
- •Байт здесь, байт там, и реальные покойники
- •Восстановление памяти: проблемы
- •Удаление объектов, управляемое программистом
- •Проблема надежности
- •Проблема простоты разработки
- •Подход на уровне компонентов
- •Управление памятью связного списка
- •Работа с утилизированными объектами
- •Дискуссия
- •Автоматическое управление памятью
- •Необходимость автоматических методов
- •Что в точности понимается под восстановлением?
- •Подсчет ссылок
- •Сборка мусора
- •Механизм сборки мусора
- •Основа сборки мусора
- •Сборка по принципу "все-или-ничего"
- •Продвинутый (Advanced) подход к сборке мусора
- •Алгоритмы параллельной сборки мусора
- •Практические проблемы сборки мусора
- •Класс memory
- •Механизм освобождения
- •Сборка мусора и внешние вызовы
- •Среда с управлением памятью
- •Сложные проблемы
- •Перемещение объектов
- •Механизм сборки мусора
- •Повышенное чувство голода и потеря аппетита (Bulimia and anorexia)
- •Операции сборщика мусора
- •Ключевые концепции
- •Библиографические заметки
- •Упражнения у9.1 Модели создания объектов
- •Горизонтальное и вертикальное обобщение типа
- •Необходимость параметризованных классов
- •Родовые атд
- •Проблема
- •Роль типизации
- •Родовые классы
- •Объявление родового класса
- •Использование родового класса
- •Терминология
- •Проверка типов
- •Правило типизации
- •Операции над сущностями родового типа
- •Типы и классы
- •Массивы
- •Массивы как объекты
- •Свойства массива
- •Размышления об эффективности
- •Синонимичная инфиксная операция
- •Стоимость универсализации
- •Обсуждение: что все-таки не сделано
- •Ключевые концепции
- •Библиографические замечания
- •Упражнения у10.1 Ограниченная универсализация
- •У10.2 Двумерные массивы
- •У10.3 Использование своего формального родового параметра фактически как чужого
- •Лекция 11. Проектирование по контракту: построение надежного по
- •Базисные механизмы надежности
- •О корректности по
- •Выражение спецификаций
- •Формула корректности
- •Сильные и слабые условия
- •Введение утверждений в программные тексты
- •Предусловия и постусловия
- •Класс стек
- •Предусловия
- •Постусловия
- •Педагогическое замечание
- •Контракты и надежность по
- •Права и обязательства
- •Интуиция (Дзен) и искусство программной надежности: больше гарантий и меньше проверок
- •Утверждения не являются механизмом проверки вводимых данных
- •Утверждения это не управляющие структуры
- •Ошибки, дефекты и другие насекомые
- •Работа с утверждениями
- •Класс стек
- •Императив и аппликатив (применимость)
- •Замечание о пустоте структур
- •Проектирование предусловий: толерантное или требовательное?
- •Предусловия и статус экспорта
- •Толерантные модули
- •Инварианты класса
- •Определение и пример
- •Форма и свойства инвариантов класса
- •Инвариант в момент изменения
- •Кто должен обеспечить сохранность инвариантов
- •Роль инвариантов класса в программной инженерии
- •Инварианты и контракты
- •Когда класс корректен?
- •Корректность класса
- •Роль процедур создания
- •Ревизия массивов
- •Связывание с атд
- •Не просто коллекция функций
- •Компоненты класса и атд функции
- •Выражение аксиом
- •Функция абстракции
- •Инварианты реализации
- •Инструкция утверждения
- •Инварианты и варианты цикла
- •Трудности циклов
- •Сделаем циклы корректными
- •Ингредиенты доказательства корректности цикла
- •Синтаксис цикла
- •Использование утверждений
- •Утверждения как средство для написания корректного по
- •Использование утверждений для документирования: краткая форма класса
- •Мониторинг утверждений в период выполнения
- •Каков оптимальный уровень мониторинга?
- •Обсуждение
- •Нужен ли мониторинг в период выполнения?
- •Выразительная сила утверждений
- •Включение функций в утверждения
- •Инварианты класса и семантика ссылок
- •Что дальше
- •Ключевые концепции
- •Библиографические замечания
- •Лекция 12. Когда контракт нарушается: обработка исключений
- •Базисные концепции обработки исключений
- •Исключения
- •Источники исключений
- •Ситуации отказа
- •Обработка исключений
- •Как не следует делать это - c-Unix пример
- •Как не следует делать это - Ada пример
- •Принципы обработки исключений
- •Цепочка вызовов
- •Механизм исключений
- •Спаси и Повтори (Rescue и Retry)
- •Как отказаться сразу
- •Примеры обработки исключений
- •Поломки при вводе
- •Восстановление при исключениях, сгенерированных операционной системой
- •Повторение программы, толерантной к неисправностям
- •Задача предложения rescue
- •Корректность предложения rescue
- •Четкое разделение ролей
- •Когда нет предложения rescue
- •Продвинутая обработка исключений
- •Запросы при работе с классом exceptions
- •Какой должна быть степень контроля?
- •Исключения разработчика
- •Обсуждение
- •Дисциплинированные исключения
- •Должны ли исключения быть объектами?
- •Методологическая перспектива
- •Ключевые концепции
- •Библиографические замечания
- •Упражнения у12.1 Наибольшее целое
- •У12.2 Объект Exception
- •Лекция 13. Поддерживающие механизмы
- •Взаимодействие с не объектным по
- •Внешние программы
- •Улучшенные варианты
- •Использование внешних программ
- •Вопрос совместимости: гибридный программный продукт или гибридные языки?
- •Передача аргументов
- •Инструкции
- •Вызов процедуры
- •Присваивание (Assignment)
- •Создание (Creation)
- •Условная Инструкция (Conditional)
- •Множественный выбор
- •Проверка
- •Отладка
- •Повторение вычислений
- •Выражения
- •Манифестные константы
- •Вызовы функций
- •Текущий объект
- •Выражения с операторами
- •Нестрогие булевы операторы
- •Ввод и вывод
- •Лексические соглашения
- •Ключевые концепции
- •Многоугольники
- •Прямоугольники
- •Основные соглашения и терминология
- •Наследование инварианта
- •Наследование и конструкторы
- •Пример иерархии
- •Полиморфизм
- •Полиморфное присоединение
- •Что на самом деле происходит при полиморфном присоединении?
- •Полиморфные структуры данных
- •Типизация при наследовании
- •Согласованность типов
- •Пределы полиморфизма
- •Экземпляры
- •Статический тип, динамический тип
- •Обоснованы ли ограничения?
- •Может ли быть польза от неведения?
- •Когда хочется задать тип принудительно
- •Полиморфное создание
- •Динамическое связывание
- •Использование правильного варианта
- •Переопределение и утверждения
- •О реализации динамического связывания
- •Отложенные компоненты и классы
- •Движения произвольных фигур
- •Отложенный компонент
- •Эффективизация компонента
- •Отложенные классы
- •Соглашения о графических обозначениях
- •Что делать с отложенными классами?
- •Задание семантики отложенных компонентов и классов
- •Способы изменения объявлений
- •Повторное объявление функции как атрибута
- •Обратного пути нет
- •Использование исходной версии при переопределении
- •Смысл наследования
- •Двойственная перспектива
- •Взгляд на класс как на модуль
- •Взгляд на класс как на тип
- •Наследование и децентрализация
- •Независимость от представления
- •Парадокс расширения-специализации
- •Роль отложенных классов
- •Назад к абстрактным типам данных
- •Отложенные классы как частичные интерпретации: классы поведения
- •Не вызывайте нас, мы вызовем вас
- •Программы с дырами
- •Роль отложенных классов при анализе и глобальном проектировании
- •Обсуждение
- •Явное переопределение
- •Доступ к предшественнику процедуры
- •Динамическое связывание и эффективность
- •Оценка накладных расходов
- •Статическое связывание как оптимизация
- •Кнопка под другим именем: когда статическое связывание ошибочно
- •Ключевые концепции
- •Библиографические замечания
- •У14.5 Классы без объектов
- •У14.6 Отложенные классы и прототип
- •У14.7 Библиотека поиска в таблицах (семестровый проект)
- •У14.8 Виды отложенных компонентов
- •У14.9 Комплексные числа
- •Лекция 15. Множественное наследование
- •Примеры множественного наследования
- •Пример, неподходящий для введения
- •Может ли самолет быть имуществом?
- •Числовые и сравнимые значения
- •Окна - это деревья и прямоугольники
- •Деревья - это списки и их элементы
- •Составные фигуры
- •Брак по расчету
- •Структурное наследование
- •Наследование функциональных возможностей
- •Лунка и кнопка
- •Переименование компонентов
- •Конфликт имен
- •Результат переименования
- •Смена имен и переопределение
- •Подбор локальных имен
- •Играем в имена
- •Использование родительской процедуры создания
- •Плоские структуры
- •Плоская форма класса
- •Применение плоской формы
- •Краткая плоская форма
- •Дублируемое наследование
- •Общие предки
- •По обе стороны океана
- •Совместное использование и репликация
- •Ненавязчивое дублирующее наследование
- •Правило переименования
- •Конфликт переопределений
- •Конфликт при совместном использовании: отмена определения и соединение компонентов
- •Конфликты при репликации: выделение
- •Выделение всех компонентов
- •Сохранение исходной версии при переопределении
- •Пример повышенной сложности
- •Дублируемое наследование и универсальность
- •Правила об именах
- •Обсуждение
- •Переименование
- •Ключевые концепции
- •У15.7 Деревья
- •У15.8 Каскадные или "шагающие" (walking) меню
- •Инварианты
- •Предусловия и постусловия при наличии динамического связывания
- •Как обмануть клиентов
- •Как быть честным
- •Устранение посредника
- •Субподряды
- •Абстрактные предусловия
- •Правило языка
- •Повторное объявление функции как атрибута
- •Замечание математического характера
- •Глобальная структура наследования
- •Универсальные классы
- •Нижняя часть иерархии
- •Универсальные компоненты
- •Замороженные компоненты
- •Запрет повторного объявления
- •Фиксированная семантика компонентов copy, clone и equality
- •Не злоупотребляйте замораживанием
- •Ограниченная универсальность
- •Вектора, допускающие сложение
- •Ограничение родового параметра
- •Игра в рекурсию
- •И снова неограниченная универсальность
- •Попытка присваивания
- •Когда правила типов становятся несносными
- •Проблема
- •Механизм решения
- •Правильное использование попытки присваивания
- •Типизация и повторное объявление
- •Устройства и принтеры
- •Одно- и двусвязные элементы
- •Правило повторного объявления типов
- •Закрепленные объявления
- •Несогласованность типов
- •Примеры из практики
- •Серьезное затруднение
- •Понятие опорного элемента
- •Опорный элемент Current
- •Еще раз о базовых классах
- •Правила о закрепленных типах
- •Когда не используются закрепленные объявления
- •Статический механизм
- •Наследование и скрытие информации
- •Применение
- •Зачем нужна такая гибкость?
- •Интерфейс и повторное использование реализаций
- •Слово в защиту реализаций
- •Два стиля
- •Выборочный экспорт
- •Ключевые концепции
- •Лекция 17. Типизация
- •Проблема типизации
- •Базисная конструкция
- •Статическая и динамическая типизация
- •Правила типизации
- •Реализм
- •Пессимизм
- •Статическая типизация: как и почему
- •Преимущества
- •Аргументы в пользу динамической типизации
- •Типизация: слагаемые успеха
- •"Типизирована ли кроха"?
- •Типизация и связывание
- •Ковариантность и скрытие потомком
- •Ковариантность
- •Параллельные иерархии
- •Своенравие полиморфизма
- •Скрытие потомком
- •Корректность систем и классов
- •Практический аспект
- •Корректность систем: первое приближение
- •Контравариантность и безвариантность
- •Использование родовых параметров
- •Типовые переменные
- •Полагаясь на закрепление типов
- •Глобальный анализ
- •Остерегайтесь полиморфных кэтколлов!
- •Назад, в Ялту
- •Одно правило и несколько определений
- •Полное соответствие
- •Ключевые концепции
- •Библиографические замечания
- •Лекция 18. Глобальные объекты и константы
- •Константы базовых типов
- •Атрибуты-константы
- •Использование констант
- •Константы пользовательских классов
- •Константы с манифестом для этого непригодны
- •Однократные функции
- •Применение однократных подпрограмм
- •Разделяемые объекты
- •Однократные функции с результатами базовых типов
- •Однократные процедуры
- •Параметры
- •Однократные функции, закрепление и универсальность
- •Константы строковых типов
- •Unique-значения
- •Обсуждение
- •Инициализация: подходы языков программирования
- •Строковые константы
- •Unique-значения и перечислимые типы
- •Ключевые концепции
Компоненты-операции
Рассмотрение выражения:
x + a
приводит к важному понятию компонента-операции (operator feature) . Это понятие может восприниматься как чисто косметическое, имеющее только синтаксическую значимость, и реально не вносящее ничего нового в ОО-метод. Но именно такие синтаксические свойства способны существенно облегчить жизнь разработчика, если они существуют, и сделать ее убогой, если их нет. Компоненты-операции являются хорошим примером успешного использования ОО-парадигмы в давно известных областях.
Для реализации этой идеи нужно догадаться, что выражение x + a содержит не один вызов (компонента x ), а два. В вычислениях, не использующих объектный подход, + рассматривается как операция сложения двух значений x и a типа REAL . Как уже отмечалось, в чистой ОО-модели единственным механизмом вычислений является вызов компонентов. Следовательно, можно считать, по крайней мере теоретически, что и сложение является вызовом соответствующего компонента.
Для лучшего понимания необходимо обсудить определение типа REAL . Сформулированное ранее объектное правило (лекция 7) подразумевает, что каждый тип основан на каком-то классе. Это в равной мере относится к предопределенным классам, аналогичным REAL , и к классам, определенным разработчиком, таким как POINT . Предположим, что необходимо описать REAL как класс. Нетрудно определить набор существенных компонентов: арифметические операции (сложение, вычитание, изменение знака...), операции сравнения (меньше чем, больше чем...). Итак, первый набросок будет выглядеть так:
indexing
description: "Действительные числа (не окончательная версия!)"
class REAL feature
plus (other: REAL): REAL is
-- Сумма текущего значения и other
do
...
end
minus (other: REAL) REAL is
-- Разность между текущим значением и other
do
...
end
negated: REAL is
-- Текущее значение, взятое с противоположным знаком
do
...
end
less_than (other: REAL): BOOLEAN is
-- Текущее значение меньше чем other?
do
...
end
... Другие компоненты ...
end
При использовании такого описания класса уже нельзя более записывать арифметическое выражение в виде: x + a . Вместо этого надо использовать следующий вызов:
x.plus (a)
По аналогии, вместо привычного -x следует теперь писать x.negated .
Можно попытаться оправдать такой отход от привычной математической нотации стремлением к последовательной реализации ОО-модели и призвать в качестве примера Lisp для обоснования возможности отхода от стандартной нотации в сообществе разработчиков ПО. Но такой аргумент нельзя считать убедительным: использование Lisp было всегда весьма ограниченным. Отход от нотации, существующей уже много столетий и знакомой всем с начальной школы, чрезвычайно опасен. Тем более что в этой нотации нет ничего неправильного.
Простой синтаксический прием позволяет сохранить последовательность подхода (требование унификации вычислительного механизма, основанного на вызове компонент) и обеспечивает совместимость с традиционной нотацией. Достаточно рассматривать выражение вида
x + a
как вызов дополнительного компонента класса REAL . Для реализации такого подхода необходимо переписать компоненту plus таким образом, чтобы для ее вызовов использовать знак операции, а не точечную нотацию. Вот описание класса, реализующее эту цель:
indexing
description: "Real numbers"
class REAL feature
infix "+" (other: REAL): REAL is
-- Сумма текущего значения и other
do
...
end
infix "-" (other: REAL) REAL is
-- Разность между текущим значением и other
do
...
end
prefix "-": REAL is
-- Текущее значение, взятое с противоположным знаком
do
...
end
infix "<" (other: REAL): BOOLEAN is
-- Текущее значение меньше чем other?
do
...
end
... Other features ...
end
Введены два новых ключевых слова - infix и prefix . Единственное синтаксическое новшество заключается в том, что имена компонент не являются идентификаторами (такими как distance или plus ), а записываются в одной из двух форм (В следующей лекции будет показано, как определить "развернутый класс". См. "Роль развернутых типов".)
infix "§"
prefix "§"
где § заменяется конкретным знаком операции (+, -, *, <, <= и др.). Компонент может иметь имя в инфиксной форме только если является функцией с одним аргументом, примерами могут служить plus , minus и less_than в первоначальной версии класса REAL . Префиксная форма может использоваться только для функций без аргументов или атрибутов.
Инфиксные и префиксные компоненты, называемые далее компоненты-операции (operator features) , используются аналогично именованным компонентам (identifier features) . Существуют лишь два синтаксических различия. Для имен компонентов-операций при их объявлении используются формы infix "§" или prefix "§", а не идентификаторы. Вызов компонентов-операций в случае инфиксных компонент имеет вид:
u § v
для префиксных:
§ u
Компоненты-операции поддерживают только квалифицированные вызовы. Неквалифицированный вызов plus (y) в подпрограмме первой версии класса REAL во второй версии должен быть записан в виде Current + y . Для именованных компонентов аналогичная нотация Current.plus (y) допустима, но обычно не используется.
Кроме указанных отличий во всем остальном компоненты-операции полностью синтаксически эквиваленты именованным компонентам, в частности могут наследоваться обычным образом. Не только базовые классы аналогичные REAL , но и любые другие, могут использовать компоненты-операции, например для функции сложения двух векторов в классе VECTOR вполне допустимо использовать инфиксную компоненту "+".
Операции, используемые в компонентах-операциях, должны подчиняться следующим правилам. Знак операции - последовательность из одного или более отображаемых символов, не содержащая пробелов и переводов строки, причем первым символом может быть только один из ниже перечисленных:
+ - a / < > = ^ @ # | &
Ограничения, налагаемые на первый символ, облегчают распознавание инфиксных и префиксных операций.
Кроме того, для совместимости с традиционной нотацией для булевых выражений следующие ключевые слова используются для обозначения операций:
not and or xor and then or else implies
Базовые классы (INTEGER и другие) используют так называемые стандартные операции:
[x]. префиксные: + - not
[x]. инфиксные: + - a / < > <= >= = // \ ^ and or xor and then or else implies .
Здесь // обозначает целочисленное деление, \ - остаток при целочисленном делении, ^ - операцию возведения в степень, xor - исключающее "или". В классе BOOLEAN and then и or else являются вариантами and и or (отличия обсуждаются далее), implies обозначает импликацию: выражение a implies b эквивалентно ( not a ) or else b .Операции, не входящие в число "стандартных", называют свободными операциями. Приведем два примера свободных операций.
[x]. Далее в классе ARRAY будет использован инфиксный компонент-операция "@" для функции, возвращающей указанный элемент массива. Обращение к i -ому элементу массива будет выглядеть как a @ i .
[x]. В класс POINT вместо функции distance можно ввести компонент-операцию "|-| " и расстояние между точками p1 and p2 будет записываться в виде p1 |-| p2 , а не как p1.distance(p2) .
Все операции имеют фиксированный приоритет, стандартные операции имеют свой обычный приоритет, а все свободные операции обладают более высоким приоритетом.
Использование компонентов-операций позволяет использовать общепринятую нотацию для выражений и одновременно отвечает требованиям полной унификации системы типов. Реализация арифметических и булевых операций как компонентов класса INTEGER вовсе не должна быть причиной снижения производительности. Концептуально a + x является вызовом компонента, но хороший компилятор может создать в результате обработки такого вызова код не менее эффективный, чем компиляторы C, Pascal, Ada или других языков, в которых "+" это жестко зафиксированная языковая конструкция.
В большинстве случаев мы можем забыть о том, что использование операций в выражениях фактически является вызовом процедур, поскольку конечный эффект будет таким же, как и при традиционном подходе. В то же время приятно сознавать, что и в этом случае не допущено отхода от принципов ОО-подхода.