Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Языки программирования. Концепции и принципы
.pdf
Объектно/ориентированное программирование
431
определенные для дуг, всюду перекрывают виртуальные операции, определенные
для окружностей, в том числе и в самих операциях для окружностей. Ради послед
него огород и городился!
Имена непосредственных компонент объекта должны быть уникальными как
в объявлении объектного типа, так и во всех его обогащениях – коллизии имен
обычных полей не допускаются, а повторное использование имен операций раз
решено только при замене виртуальных операций при обогащении объектного
типа. (Профили всех одноименных виртуальных операций должны совпадать!
Сравните с Адой и примером в Обероне.)
Тем самым становится особенно важным давать атрибутам объекта имена, от
ражающие их содержательные роли не только в создаваемой программе, но по
возможности и во всех мыслимых ее развитиях, – ведь эти имена становятся «клю
чевыми параметрами» развития программы.
По умолчанию для операций применяется статическое связывание (связыва
ние при объявлении типа и, следовательно, уже фиксированное при трансляции
определяющего этот тип модуля). Для
виртуальных операций применяется так
называемое отложенное (задержанное) связывание с их именами. Это связыва
ние при объявлении обогащенного типа, не завершенное при трансляции опреде
ляющего модуля для исходного типа и, следовательно, требующее завершения
при трансляции или исполнении определяющего модуля для обогащенного типа,
в Турбо Паскале выполняется посредством ТВО.
Заметим, что обычно атрибутыполя не относят к абстрактным атрибутам.
Однако классификация атрибутов по степени их настраиваемости (конкретные,
виртуальные, поля) не только помогает в очередной раз почувствовать пользу
единого взгляда на абстракциюконкретизацию в ЯП (в частности, выделение аб
стракции связывания), но и предсказать появление в перспективе ЯП, где будут
правила, настраиваемые как с точностью до типа, так и с точностью до экземпля
ра, и даже с точностью до конкретного исполнения экземпляра. Мы приходим
к полностью динамическому связыванию операций, аппарат для которого уже
продемонстрирован примером в Обероне.
С другой стороны, фактически и сейчас применяется оптимизация представления
объектов, состоящая в том, что в объектах, к которым нет обращений с виртуальны
ми правилами, не помещается ссылка на ТВО. Нетрудно представить себе возмож
ность привязки к объекту виртуальной операции не динамически через ТВО,
а прямой ссылкой на тело правила, настроенного на конкретный экземпляр объек
та. Такая настройка может быть оправдана многократным выигрышем в скорости
за счет систематической специализации тела операции по всем правилам конкре
тизирующего программирования.
7.5. Критерий Дейкстры
В свое время Дейкстра, размышляя о том, какие процедуры следует выделять спе
циальными ключевыми словами, – рекурсивные или нерекурсивные, пришел
к выводу, что выделять следует ИСКЛЮЧЕНИЯ из общего правила, достойные

432
оптимизации (то есть процедуры НЕрекурсивные). Другими словами, если про
граммист не указал явно, что процедура нерекурсивная, а компилятор не сумел
самостоятельно распознать ее нерекурсивность при любых допустимых значени
ях параметров, то последний обязан считать ее (потенциально) рекурсивной и со
ответственно транслировать (возможно, менее эффективно, чем в нерекурсивном
случае).
При таком решении автора ЯП, с одной стороны, усилия программиста требу
ются лишь тогда, когда нужна оптимизация, причем эти усилия требуются на
формирование некоторого ЗАПРЕТА (на использование определяемого про
граммного объекта), имеющего целью экономию машинных ресурсов.
Когда же ЯП по умолчанию предполагает исключение из общего правила, ори
ентированное на оптимизацию, а технологически наиболее оправданный общий
случай трактует как вариант, требующий специальных указаний программиста,
то это, во5первых, провоцирует ошибки, во5вторых, засоряет программу и, нако
нец, в5третьих, отвлекает внимание программиста на проблемы оптимизации от
существенно более важных проблем правильности и надежности программы. На
зовем этот критерий выбора для автора ЯП критерием Дейкстры. Этот критерий
становится все более актуальным по мере роста цены живого труда по сравнению
с ценой машинных ресурсов.
К сожалению, авторы ЯП Турбо Паскаль 5.5 не учли критерия Дейкстры (или
не стали им руководствоваться), когда решили выделять ключевым словом virtual
виртуальные операции, вместо того чтобы считать содержательно виртуальными
любые процедуры из объявлений объектного типа, про которые не сказано явно
обратное (для чего можно использовать, например, ключевое слово own). До
статочно взглянуть на объявления типов Points и Circle, которые пестрят словом
virtual, чтобы усомниться в том, что авторы поступили удачно.
А если вспомнить, что программист, не написавший этого сакраментального
слова, ограничивает развиваемость (а следовательно, и тиражируемость) своей
программы, причем не только в угоду эффективности, но и по ошибке, которая
может быть обнаружена через годы эксплуатации программы (когда потребуется,
наконец, обогатить именно то ее свойство, которое оказалось зависимым от опе
рации, не объявленной в свое время виртуальной, – кстати, тестировать свой5
ство развиваемости программы – особая проблема), становится совершенно яс
ным, что такое авторское решение следует признать недальновидным. Самое
неприятное – в том, что исправить его практически невозможно – работает прин
цип консерватизма языковых ниш. Оцените глубину критерия Дейкстры!
Перспективы языков программирования
7.6. Объекты и классы в ЯП СимулаE67
Уместно вспомнить здесь о Симуле67 как первом объектноориентированном
ЯП [36, 37]. Поразительно, сколь точно авторы этого классического ЯП угадали
перспективы программирования. Нетрудно провести прямые аналогии только
что рассмотренных понятий из самых современных ЯП и понятий Симулы67.
Для краткости понятия последнего будем выделять приставкой «с».

Объектно/ориентированное программирование
Действительно, склассы – это типы объектов с квазидинамическим контро
лем (контроль по квалификации сссылок, то есть типу указателей). Объект – это
скласс (возможно, со своим квазипараллельным исполнением, то есть соткреп
ленный). Обогащение (наследование) – это определение сподкласса с дополни
тельными атрибутами. При этом старые операции применимы к новым объектам
и присваивания «старым» сссылкам новых объектов возможно (но не наобо
рот) – это управляется квалификацией сссылок (как уже отмечено, аналог типо
вого контроля, кстати, частично статического – динамика требуется, например,
когда сссылка родительского класса присваивается сссылке на потомка, – такое
может быть и корректным, если на самом деле родительская ссылка является
ссылкой на потомка (имеет право)).
Суправление видимостью развито удивительно для классического ЯП, непос
редственно наследовавшего блочную идеологию Алгола60, и неплохо обслужи
вает объектную ориентацию языка (хотя, конечно, не учитывает модульности,
которой в эталонном языке нет).
Соперации – это активные атрибуты собъектов, и действуют они «в рамках
собъектов» (то есть сами доступны (из других объектов!) – только через ссылку
на собъект). При этом аргументом операции может служить любая компонента
использующего эту операцию контекста (в соответствии со спецификацией ее па
раметров). Если бы еще запретить прямой доступ к «пассивным» атрибутам
собъектов, получился бы чистый аппарат для реализации абстрактных типов
данных (атрибутыоперации скласса – это и есть операции соответствующего аб
страктного типа данных). Однако в реальной Симуле67 такие «абстрактные
типы» не защищены от разрушения.
Виртуальные операции – это почти в точности свиртуальные операции. При
чем и авторы Симулы67 не учли критерия Дейкстры – свиртуальные операции
нужно выделять словом virtual.
Сдистанционные идентификаторы аналогичны обычным выборкам по селек
торам. Интересно подчеркнуть, что чем шире область возможных значений ссы
лочной переменной (в соответствии с ее квалификацией, то есть типом), тем
меньше атрибутов с ее помощью можно указать – это естественное следствие
иерархии (обогащения) объектов. Однако в Симуле67 можно снять запрет на об
ращение к атрибутам подклассов из надкласса (из бедного к обогащенному, из
родительского к потомку) за счет явной разрешающей «оперативной» квалифи
кации «qua»:
Родитель qua потомок.атрибут_потомка
Такое может понадобиться, когда фрагмент программы «выпадает из иерар
хии» и его проще всего поместить в родительский класс (например, для организа
ции в нем взаимодействия между объектамипотомками из разных классов).
Другими словами, если нельзя, но очень хочется, то можно, но при этом нужно
явно сообщить транслятору о сознательном нарушении запрета. В подобном стиле
действуют и авторы других «строгих» ЯП. Например, в Аде можно обойти конт
роль типов, применив «фиктивное» преобразование типов посредством специально
для этой цели предназначенной родовой функции UNCHECKED_CONVERSION.
433

434
Вместе с тем Симула67 на практике не смогла конкурировать с ЯП, не содер
жавшими столь перспективных идей, хотя и была вполне справедливо представ
лена авторами как «универсальный язык программирования» [36]. Не говоря уж
о том, что этот ЯП явно опередил свое время, – масса программистов оказалась
просто не готова воспринимать его ценности. Повидимому, важнейшим его недо
статком оказалась относительно низкая эффективность исполняемых программ.
Дело в том, что в Симуле67 почти все интерпретируется (это же характерно и
для Смолтока), а не компилируется, как в Турбо Паскале 5.5. В частности, нет
статического создания объектов – они создаются динамически генераторами, нет
статического контроля объектных типов (то есть квалификации сссылок – в об
щем случае она контролируется динамически). Для относительной неудачи Си
мулы67 сыграло свою роль и полное отсутствие средств модуляризации (раз
дельной компиляции) на уровне эталонного языка. В более современных
реализациях они, конечно, имеются (в частности, на отечественных компьютерах
БЭСМ6 и ЕС [37]). С этой точки зрения, ЯП Симула67 унаследовал важнейший
недостаток своего непосредственного предшественника и подмножества – Алго
ла60, проигравшего Фортрану прежде всего изза отсутствия модулей.
Кроме того, нет разделения спецификации и реализации. Как уже отмечалось,
нет защиты от несанкционированного доступа – контролируется только квали
фикация ссылок, которой программист всегда может управлять, зная структуру
программы (а не знать ее не может, так как при отсутствии разделения специфи
кации и реализации, а также (в общем случае) раздельной компиляции вся она
нужна для его работы). С другой стороны, авторы [37] утверждают, что можно
иметь атрибуты, доступные только через соответствующие процедуры. Остается
неясным, каким способом (в приведенном ими объяснении примера в [37, стр. 33–
34] имеются противоречия).
Перспективы языков программирования
7.7. Перспективы,
открываемые объектной ориентацией
средств программирования
Хотя мы рассмотрели далеко не все заслуживающие внимания примеры совре
менных ЯП (а также аспекты) объектной ориентации, накоплено достаточно ма
териала для обсуждения открываемых ею перспектив. Среди таких ЯП нужно на
звать, по крайней мере, Смолток (в особенности Смолток/5 286) и Си++, а среди
аспектов – переход от явного вызова операций к обмену сообщениями между
объектами.
Будем считать последнюю идею понятной без специальных пояснений – дос
таточно представить себе, что каждый объект снабжен анализатором сообщений,
вызывающим при необходимости соответствующую операцию этого объекта.
Другими словами, каждый объект снабжен минитранслятором сообщений, уст
роенным, например, по принципу синтаксического управления. Конечно, в общем

Объектно/ориентированное программирование
случае такой подход требует значительных затрат на анализ сообщений в период
исполнения программы. Однако при определенных ограничениях на класс сооб
щений возможна весьма глубокая оптимизация (в перспективе с учетом конкре
тизирующего программирования). Во всяком случае, прямой вызов операций по
статически известным именам – частный случай обмена сообщениями.
По убеждению автора, объектная ориентация знаменует и стимулирует прин
ципиально новый уровень развития средств программирования (ЯП, в частности)
потому, что позволяет естественно сочетать практически все рассмотренные нами
(и некоторые иные) перспективные тенденции, тем самым создавая почву и для
следующего витка развития (полезно в этой связи обратить внимание, например,
на идеологию ЯП Оккам2 с его асинхронными процессамиобъектами и канала
ми для обмена сообщениями), а также на отечественный язык НУТ [38] с его изящ
ным соединением объектноориентированного, реляционного и концептуального
программирования. Рассмотрим коротко представляющиеся наиболее интерес
ными проблемы вместе с идеями их решений в рамках объектноориентированно
го программирования. Для краткости его понятия и решения будем предварять
префиксом «о».
Проблема управления
Основной оответ – децентрализация управления. Вместо представления о еди
ном исполнителе, выполняющем единую программу, создаваемую единым во мно
гих лицах «богом»программистом, предлагается мыслить в терминах коллектива
(коллективов) взаимодействующих объектовисполнителей, «живущих» в значи
тельной степени самостоятельно (с точностью до овзаимодействия) в соответ
ствии со своими собственными правилами поведения и «осоциальными» ролями.
Создание, то есть программирование, такого ообщества также следует представ
лять как довольно демократическую скорее историю, чем процедуру, существенно
использующую развиваемость оиндивидов (как типов, так и объектов), а также
относительно локальные договоренности о конкретных способах взаимодейст
вия. Такую тенденцию можно обозначить метафорой «от автархии к анархии»,
в связи с чем рассматриваемый стиль программирования можно назвать «анархо
ориентированным», если в соответствии с современными воззрениями снять
с понятия «анархия» привкус априорного неприятия.
435
Проблема взаимодействия
Основной оответ (в перспективе) – относительно локальное взаимопонима
ние на основе взаимоприемлемого языка сообщений, совершенно не обязательно
единого и понятного для всех. Более того, глубина понимания конкретных сооб
щений участниками взаимодействия также может легко варьироваться в зависи
мости от их роли в решении совместных задач.
Проблема ресурсов
Основной оответ – разнообразие как самих ресурсов, так и способов их созда
ния, предоставления и изъятия по соответствующим операциямзапросамсооб
щениям соответствующими объектами. В принципе, в эту схему укладываются
любые мыслимые варианты и их оптимизации.

436
Проблема развития
Основной оответ – идеал наследуемости. Однако в общей перспективе его
следует дополнить динамизмом (вплоть до построения обогащенных объектов
при работе других объектов), сближением понятия модуля с понятием объекта
(объектного типа, класса), а также наследуемостью в языке обмена сообщениями.
Проблема защиты
И здесь основной оответ – идеал наследуемости, дополненный динамизмом
при контроле корректности сообщений, а также в общем случае принципиальной
невозможностью разрушить объект, если соответствующий приказсообщение не
входит в согласованный язык сообщений.
Проблема классификации (типизации)
Основная метафора оответа – тип = язык. Эту метафору можно раскрыть и
так, что типизация охватывает любые языковые конструкты (данные, операции,
их сочетания – это путь к универсальному конструктиву типа [28]), и так, что
средства описания типа тесно переплетаются со средствами определения полного
языка (ведь при определении типа объектов нужно определять и воспринимае
мый ими язык сообщений). Одно из «экстремистских», но не лишенных смысла
толкований – к одному типу относятся объекты, «понимающие» определенный
язык (или подъязык), обеспечивающий взаимодействие. [Так недалеко и до
объектной нации.]
Проблема модульности
Общий оответ – модуль = объект (объектный тип). Существующие различия
между этими понятиями связаны с особой ролью трансляции в жизненном цикле
программы. Необходимость анализа и интерпретации сообщений в качестве ас
пектов функционирования объектов превращает трансляцию в одну из рядовых
операций и тем самым сближает логическую структуру программы с ее физиче
ской структурой.
Перспективы языков программирования
Проблема свободы
Проблема свободы и ответственности естественно возникает перед каждой
творческой личностью, в том числе (и в весьма острой форме) – перед программи
стом. Поскольку объектная ориентация – специфический стиль программистско
го мышления, а также определенная совокупность средств программирования,
предоставляемая ЯП, интересно понять, какие ответы возможны в ее рамках.
Известно, что свобода хороша до тех пор, пока она не ограничивает свободу
индивида, претендующего на тот же уровень свободы. С этой точки зрения основ
ной оответ – единственным источником любых ограничений на свободу по
ведения объекта служит требование взаимопонимания (корректного обмена
сообщениями) со всеми, кто ему самому необходим (для выполнения осоци
альной роли).
Частным случаем такого требования служат и ресурсные ограничения, по
скольку в общем случае ресурсы по требованию объекта предоставляются ему
другими объектами. Другой частный случай – описание характера обмена сооб

Объектно/ориентированное программирование
щениямиоперациями в спецификации и полная свобода реализации при условии
воплощения требований спецификации.
Таким образом, объектная ориентация действительно в максимальной степени
способствует свободному сочетанию самых разнообразных подходов к програм
мированию отдельных объектов (объектных типов), требуя в общем случае лишь
относительно локальных соглашений о необходимом «взаимопонимании» пере
даваемых сообщений.
Проблема ответственности
Основной оответ – полная защита от несанкционированного (языком сооб
щений) вмешательства в поведение объекта, в результате чего его создатель по
лучает возможность полностью отвечать за корректность его поведения. Другими
словами, никто не может заставить объект сделать то ( или сделать с ним то), чего
объект не «понимает» и (или) не «контролирует» (ведь любое сообщение в общем
случае анализируется самим объектом).
437
7.8. Свойства объектной ориентации
Новый уровень абстракции
Объектная ориентация ведет за счет нового уровня абстракции к обновлению
фундаментальных концепций ЯП – управления, развития, защиты, классифика
ции, модульности, динамизма (высокоразвитой типизацией), параллелизма (на
следуемостью), спецификации, реализации, жизненного цикла программы (рас
слоенным программированием и др.) – и в целом к сближению проблематики ЯП
с проблематикой представления знаний и искусственного интеллекта.
Например, очевидно сходство используемого в объектноориентированном
подходе понятия объекта с понятием фрейма – одним из основных в современном
представлении знаний. Понятие объекта можно считать одним из воплощений
(своего рода конкретизацией) понятия фрейма. Стереотипная ситуация – это
объектный тип, слоты – это поля и (или) операции (правила поведения), играю
щие вполне определенную роль в рассматриваемой стереотипной ситуации, кон
кретная ситуация – это экземпляр объекта.
Интеграция понятий и средств информатики
Объектноориентированное программирование знаменует очередной этап
сближения (интеграции) понятий и средств информатики, характерный для нее
в последние годы и проявляющийся не только в названных областях, но и в созда
нии интегрированных сред (вспомните о назначении ЯП Оберон), в сближении
ЯП и СУБД (экспортное окно – аналог концептуальной схемы в СУБД, реляци
онный ЯП близок к языку запросов реляционной БД), ЯП и языков логического
программирования (вспомните о родстве Рефала с Прологом) и др.
Целостность ЯП
Наш анализ в очередной раз демонстрирует, что ЯП – целостная система. За
тронув лишь одно его свойство – развиваемость, мы на основе принципа концеп

438
туальной целостности «вытащили» новый взгляд почти на все аспекты ЯП. Если
бы не уже отмеченный естественный консерватизм языковых ниш, ЯП уже могли
бы стать совершенно иными. Искусство авторов новейших ЯП «объектной» ориен
тации проявилось, в частности, в том, что такие ЯП, как Оберон, Турбо Паскаль
5.5 или Си++, оказались внешне очень похожими на своих более традиционных
предшественников и вместе с тем во всех отношениях плавно вводящими пользо
вателей в круг совершенно новых идей (в отличие от Симулы67 и тем более
Смолтока, где к
резким падением эффективности программ). С этим, возможно, в основном и свя
зан их меньший успех у пользователей, хотя немалую роль сыграла и неготов
ность программистской общественности к новой системе ценностей в программи
ровании, провозглашающей самым дорогим ресурсом труд квалифицированного
человека, а не, например, время работы или память компьютера.
тому же за эти весьма прогрессивные идеи нужно было платить
Перспективы языков программирования
7.9. Критерий фундаментальности
языковых концепций
Судьба объектной ориентации (от неприятия ее при появлении в Симуле67 до
современного бума) на весьма нетривиальном примере подтверждает один из ос
новных тезисов нашей книги: почти все фундаментальные концепции про
граммирования (и современных ЯП) можно объяснить, не привлекая реали
заторской позиции.
Другими словами, если необходимо привлекать реализаторскую позицию, то
концепция не фундаментальна. Это, конечно, не умаляет исключительной значи
мости применения наилучших алгоритмов и учета всех возможностей среды для
коммерческого успеха программы.
Действительно, никакая проблема реализации не мешала еще двадцать лет на
зад изготовить систему, по объектноориентированным возможностям сопоста
вимую с Турбо Паскалем 5.5 (то есть включить их, а также соответствующие мо
дульные средства, еще в первые версии Паскаля). Но само программирование
должно было созреть до понимания фундаментальной значимости удовлетворе5
ния потребности в развиваемости.

Заключительные
замечания
8.1. Реализаторская позиция ........ 440
8.2. Классификация языков
программирования........................ 448
8.3. Тенденции развития ЯП .......... 451
Глава 8

440
Перспективы языков программирования
8.1. Реализаторская позиция
В самом начале книги (стр. 29) мы выделили пять позиций, с которых намерева
лись рассмотреть ЯП. До сих пор реализаторской позиции уделялось мало внима
ния. Настало время и нам несколько подробнее поговорить о реализации ЯП.
Безусловно, возможности и требования реализации оказывают существенное
влияние на свойства ЯП. Долгое время это влияние считалось (а в значительной
степени и было) определяющим. С ростом возможностей аппаратуры и методов
трансляции оно ослабевает, уступая технологической позиции. Как уже сказано,
основной методический тезис книги состоит в том, что подавляющее большинство
свойств современных ЯП можно достаточно убедительно объяснить, не прибегая к
реализаторской позиции.
С другой стороны, о реализации ЯП написано много полезных книг (с точки зре
ния общих потребностей программистов, вполне достаточно книги [39]). Поэтому
постараемся уделить внимание лишь тем аспектам реализаторской позиции, кото
рые в доступной литературе освещены недостаточно.
Напомним роль реализатора во взаимодействии с представителями остальных
выделенных нами позиций. Реализатор призван обеспечить эксплуатацию ЯП на
всех технологических этапах, опираясь на замысел автора.
Такое понимание роли реализатора (и реализации) ЯП не стало, к сожалению,
общепринятым. Иногда еще приходится бороться с устаревшей точкой зрения,
что задача реализатора – обеспечить ЯП исполнителем (языковым процессором,
транслятором), и только. Именно такая узкая «реализаторская позиция» (имею
щая глубокие корни) – одна из причин положения, при котором мы вынуждены
пользоваться ненадежными трансляторами, колдовать над невразумительными
диагностическими сообщениями, страдать от произвольных изменений ЯП, от
сутствия сервиса, помогающего создавать и сопровождать программы, низкого
уровня учебников, отсутствия методических материалов и т. п.
Нам не удастся рассмотреть задачу реализатора во всей ее полноте достаточно
подробно. Поэтому поступим так же, как в случае технологической позиции. Как
вы помните, мы кратко рассмотрели жизненный цикл изделия в целом, а затем
выделили только проектирование как представительный этап этого цикла. Ана
логичным образом дадим общее представление о задаче реализации ЯП в целом, а
затем выделим лишь один аспект реализации и займемся только им.
Итак, будем считать, что реализация в целом должна обеспечить эксплуата
цию ЯП на всех этапах жизненного цикла комплексного программного продук
та (ЖЦКПП). Рассмотрим три этапа (стадии) жизненного цикла – проектирова
ние, эксплуатацию и сопровождение продукта. Их достаточно, чтобы выделить
важнейшие компоненты реализации.
8.1.1. Компоненты реализации
Будем исходить из того, что авторское определение ЯП имеется (для базового
языка индустриального программирования в настоящее время это обычно отрас
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
