Б. Страуструп - Дизайн и Эволюция C++. 2006 (1160775), страница 28
Текст из файла (страница 28)
У вопроса о совместимости была и другая, более важная сторона. Какими параметрами С++ должен отличаться от С, чтобы достичь своих основных целей? И в чем именно С++ должен быть совместим с С для достижения этих же целей? Оба аспекта существенны, и при переходе от С ччгЪ С1аззез к С++ пересмотр концепций производился в обоих направлениях. Медленно и мучительно было выработано соглашение о том, что между С++ и АХЯ1 С (когда появится стандарт) не будет неоправданных несовместимостей [8Ггоцзггпр, 198б), но тем не менее понятие «вынужденной несовместимости» имеет право на существование.
Естественно, вопрос о том, что считать «вынужденной несовместимостью», вызывал много споров и отнимал у меня непропорционально много времени и сил. Впоследствии появилась формулировка — «С++: настолько близко к С, насколько возможно, но не ближе», по названию работы, написанной совместно Эндрю Кенигом и мной [Коешй, 1989). Один из показателей успеха такой стратегии — все примеры из книги Кйй2 [Кепн8Ъап, 1988) написаны на С, который является подмножеством С++.
Примеры программ из КйК2 тестировались с помощью компилятора С1гопп Некоторые заключения о модульности и о том, как собирать программу из отдельно скомпилированных частей, были изложены в первой редакции справочного руководства по С++ [8ггоцз1гцр, 1984); гз имена являются закрытыми, если не объявлены открытыми; гз имена локальны в файле, где они определены, если явно не экспортированы из него; гз типы контролируются статически, если такой контроль не подавлен; о класс составляет область действия (откуда следует, что классы могут быть вложенными). Первый пункт не влияет на совместимость с С, остальные приводят к некоторым расхождениям: гз имя нелокальной функции или объекта в С по умолчанию видимо в других единицах трансляции; о в С необязательно объявлять функции перед использованием, и по умолчанию проверка типов при вызове не производится; Языки С и С++ 6ИИ>ИИКП с) имена структур в С не вкладываются (даже если лексически они вложены); а в С++ есть только одно пространство имен, тогда как в С с каждым «тэгом структуры» связано отдельное (см.
раздел 2.8.2). зсгисс оигег зегисс 1епег ( ьпс 1; ): (пс 1; ); вегасе (ппег а = ( 1 ]; вполне допустима. Более того, такого рода код встречается в стандартных заголовочных файлах системы УЫ1Х. Когда данная проблема всплыла, уже ближе к концу известных «баталий», у меня не было времени подробно изучать все последствия этого «решения» С. Гораздо проще было согласиться, чем затевать новые споры. В 1989 г., после многих технических сложностей и недовольства пользователей, вложенные области действия классов снова были введены в С++ (АЯМ] (см. раздел 13.5). Ожесточенные споры привели к тому, что для С++ был одобрен усиленный контроль типов при вызове функции (без модификаций).
Неявное нарушение статического контроля типов стало первым случаем «вынужденной» несовместимости С и С++. Комитет АХ51 С одобрил облегченный вариант правил и нотации С++ в этой области и объявил устаревшими такие виды использования, которые не отвечают правилам С++. Пришлось принять правило С о том, что глобальные имена по умолчанию видимы в других единицах трансляции. Просто не было поддержки для правила, более жестко ограничиваюшего область видимости имен. Это означало, что в С++, как и в С, не будет механизма для выражения модульности на уровне выше класса или файла. Это послужило причиной многих жалоб, пока комитет АХ31/1 8 0 не п ринял пространства имен (см. главу 17) в качестве механизма, позволяюшего избежать непреднамеренного совмещения имен.
Однако Дуг Макилрой и другие возражали, что С-программисты не оценят язык, где каждый объект и функцию, Сегодня «баталии по поводу совместимости» кажутся мелкими и скучными, яо некоторые из поднятых тогда проблем не решены до сих пор, Полагаю, причина, по которой эти «войны» так затянулись и не принесли окончательного результата, заключается в том, что мы не затрагивали более глубоких вопросов о различии целей С и С++ и видели в совместимости множество несвязанных проблем, к каждой из которых следует подходить индивидуально. Типичный пример — наименее значимый вопрос о «пространствах имен» потребовал больше всего усилий и, в конце концов, был решен путем компромисса [АЯМ].
Мне пришлось нарушить концепцию класса как области действия и принять «решение» С, иначе не разрешалось выпускать версию 1.0. При этом я не понимал, что структура в С не составляет области действия, поэтому конструкция Рождение С++ ИИИИИИИ!в которые должны быть доступны из другой единицы трансляции, придется явно объявлять таковыми. Возможно, в то время они были правы и уберегли меня от серьезной ошибки. В любом случае теперь я убежден, что первоначальное решение, предлагавшееся для С++, было не слишком изящным.
Обсуждение вопросов совместимости раскололо пользователей на два противоборствующих лагеря, и члены каждого из них были абсолютно убеждены в справедливости своей точки зрения. Первый лагерь требовал стопроцентной совместимости, часто не осознавая ее последствий. Например, многие из поборников полной совместимости с недоумением узнавали, что это приведет к несовместимости с уже существующим С++, в результате чего перестанут компилироватъся десятки миллионов строк написанного на С++ кода. Во многих случаях требование стопроцентной совместимости исходило из предположения, что у С++ мало пользователей. Нередко за этим требованием стояло желание скрыть свое незнание С++ или неприятие некоторых его новых возможностей. В другом лагере объявляли, что проблемы совместимости с С не существует вовсе, и требовали введения таких возможностей, которые вызвали бы серъезные неудобства у всех, кто хотел писать на смеси языков С и С++.
Разумеется, чем более «экстремистскими» были притязания, исходящие из одного лагеря, тем глубже окапывались представители другого, боясь потерять те возможности языка, в которых были заинтересованы. В тех случаях (к счастью, почти всегда), где учитывались истинные интересы людей и реалъные примеры использования С и С+~-, споры обычно заканчивались конструктивным рассмотрением деталей компромиссного решения. На организационном собрании комитета АХ81 ХЗД16 Ларри Рослер, первый редактор комитета АХ81 С, объяснил скептически настроенному Тому Пламу (Тош Р!пш), что «С++ — это С, каким мы пытались, но не смогли его сделать».
Возможно, данное утверждение чересчур сильно, иодля общего подмножества С и С++ оно недалеко от истины. 3.13. Инструменты для проектирования языка Рассказывая о дизайне и эволюции С++, я почти не уделил внимания теории и инструментам более сложным, чем обычная классная доска. Для работы нэд грамматикой я пытался использовать УАСС (генератор синтаксических анализаторов 1.АЬК(1)-грамматик 1АЬо, 19861), но потерпел неудачу из-за особенностей синтаксиса С (см. раздел 2.8.1). Пробовал применить денотационную семантику, тоже неуспешно. Рави Сетхи (Кау( Зе|Ь1), занимавшийся этой проблемой, понял, что не может выразить семантику С подобным способом [8еГЬЬ 19801.
Основной трудностью была нерегулярность С и большое число зависящих от реализации и неопределенных аспектов. Много позже комитет по стандартизации АХ81/180 С++ призвал экспертов по формальным определениям растолковать свои методы и инструментарий и высказать мнение о том, в какой мере формализованный подход к определению С++ будет полезен нам при стандартизации.
Я знакомился также с формальными спецификациями языков М1. и Моди!а-2, чтобы понять, поможет ли формальный подход получить более короткое и изящное описание, чем описание на обычном английском языке. Не думаю, что формальное Инструменты дпя проектирования языка ЯффффЯЯЩ описание С++ оставило бы разработчикам компиляторов и опытным пользователям меньше шансов на неправильную интерпретацию. Я пришел к выводу, что формальное описание языка, при проектировании которого какой-либо метод формального определения не использовался изначально, не под силу никому, кроме горстки экспертов в этой узкой области. Однако отказ от надежд на формальную спецификацию оставил меня один на один с неточной и недостаточной терминологией. Что можно было сделать в этой ситуации? Я рассказывал о новых возможностях языка коллегам, чтобы проверить свою логику.
Однако вскоре у меня выработалось стойкое пренебрежение ко всем имеющимся аргументам, поскольку убедительно обосновать каждую особенность языка не получалось. С другой стороны, нельзя построить язык, который был бы полезен, включая в него все, что кому-нибудь может пригодиться. Полезных возможностей слишком много, и ни в одном языке они пе могут быть объединены так, чтобы язык сохранил при этом внутреннюю целостность.
Поэтому всюду, где возможно, я старался экспериментировать. К сожалению, чистый эксперимент поставить обычно не удается. Невозможно создать две полномасштабных системы, содержащих компилятор, набор инструментальных средств и документацию, а потом попросить одну группу людей пользоваться первой, другую — второй и сравнить результаты. Реализовав то или иное средство, мы с немногими коллегами пытались применить его на практике, и я, как мог, старался проявлять крайнее недоверие ко всем положительным откликам. По мере возможности я старался учитывать мнения опытных программистов. Так я пытался компенсировать фундаментальные ограничения своих опытов, Обычно эксперимент состоял в сравнении реализаций, изучении качества исходного кода небольших примеров и в измерении производительности и потребления памяти на таких примерах.
По крайней мере, в процессе проектирования у меня была обратная связь с практиками, поэтому я мог полагаться на экспериментальные результаты, а не только на плоды абстрактных размышлений. Убежден, что проектирование языка — это не упражнение в голом теоретизировании, а тесно связанный с практикой процесс учета различных потребностей, методов и ограничений. Хороший язык не просто хорошо спроектирован, он выращен.