| Сергей Холодилов ( @ 2008-05-12 04:08:00 |
| Entry tags: | c++, книжки, программинг |
C++
Рок-н-ролл мёртв, а я ещё нет
Борис Гребенщиков
Мавр сделал свое дело, мавр может уходить
Фридрих Шиллер
(а вовсе не Шекспир, как я думал сначала)
Но он навсегда останется в нашей памяти...
Борис Гребенщиков
Мавр сделал свое дело, мавр может уходить
Фридрих Шиллер
(а вовсе не Шекспир, как я думал сначала)
Но он навсегда останется в нашей памяти...
Кучу всего разного хочется сказать про С++. Забавного и серьёзного. Начнём с забавного. Все помнят хохму про зависимость популярности языка программирования от бороды? Теперь посмотрите на домашнюю страничку Бъёрна Страуструпа и его новую фотографию... Есть ещё вопросы про C++0X? Вопросов нет, переходим к следующему пункту.
Страуструп и без нас получил полно всяческих наград. Но я считаю, что всё-таки нужно всем программистам сброситься и поставить ему памятник. Выбрать какую-нибудь бородатую фотографию и отлить из бронзы в натуральную величину. Почему - поймёте по тексту. Я его всегда уважал. Был, правда, момент, когда я вдруг осознал, что С++ - не самый лучший язык на свете... Но одновременно с этим я понял, что самых лучших языков просто не бывает. Бывают задачи и языки для них.
Что было
А недавно я прочитал

английская обложка красивее гораздо, так что пусть тут будет она :)
И зауважал Страуструпа ещё больше. Потому что он это тоже понимал, причём уже тогда, когда я ещё только рождался - как раз в 1982 году. При проектировании языка он, как Фома Аквинский, идёт срединным путём: между совместимостью с С, производительностью, гибкостью, новыми возможностями, абстракциями, ООП и низкоуровневым программированием. Не ударяется в крайности, но гнёт свою линию.
Мимо непокорных и нежных
Мимо этой и той стороны стекла
Мимо митьков и друидов
Мимо тех, кто может не пить
(c) http://www.aquarium.ru/discography/kuns
С++ - язык, разработанный не просто так, ради идеи, а для живых людей и реальных задач. Это его слабость, но это же и его сила. Можно жаловаться, что что-то недостаточно высокоуровнево или продвинуто... Но при выборе любого другого варианта он разделил бы судьбу остальных замечательных языков того времени: Eiffel, Modula-3 - его использовало бы несколько сотен разработчиков по всему миру, остальным язык бы просто не подходил.
Потому что:
- часто элементом задачи (или элементом очевидного оптимального решения) является «используя существующий код на …» Угадайте, на каком языке? На С, конечно; количество кода на других языках тогда было пренебрежимо мало по сравнению с С (ну, Фортран ещё, но Фортран из С/C++ использовать тоже можно, я даже сам как-то пробовал).
- а вторым элементом так же часто бывает «и чтобы работало быстро!» Причём на тех машинах, не на современных. Причём не просто «быстро», а «не медленнее, чем на С»
- третьим – необходимость писать код сегодня, а не переучиваться.
- четвёртым элементом... Опять же надо учесть время. Тогда писалось гораздо больше низкоуровнего системного софта.
И мы до сих пор жили бы практически в каменном веке, с доминирующим С... И перейти с С на какую-нибудь Жабу программистам было бы на порядок труднее, это другое мышление совсем, и не родилась бы та Жаба. Но нам повезло - явился добрый гений :) И подумал наконец о людях и их потребностях, а не только о красоте идеи.
С++ должен был покрывать все перечисленные "потому что". И двигаться дальше – к вершинам абстракции. Очень широкий диапазон, и нижнюю границу никак нельзя поднять, иначе всё это бесполезно – язык просто не будет использоваться. Поэтому задрать верхнюю и отказаться от опасных механизмов не получается: в прикладном коде они опасные, а в системном – необходимые.
Подборка цитат из ДиЭС++ (цитирую по русскому изданию в серии "Классика Computer Scinse", в скобках в конце номер разделов, иногда мои комментарии):
- В цифрах:
За двенадцать лет число пользователей С++ в среднем удваивалось каждые семь с половиной месяцев. (7.1) --- закон Мура отдыхает! - С.Х.
Компания Rational поставляет С++-версию библиотеки The Booch Components, которую Грейди Буч (Grady Booch) первоначально реализовал на языке Ada. На С++ её переписали сам Буч и Майк Вило (Mike Vilot). Версия на Ada занимает 125 тыс. строк исходного текста без учёта комментариев, на C++ - всего 10 тыс. строк. (8.4.1) --- Оцените прорыв в выразительности языка. И это без ущерба для эффективности! Так что сравнения с "квиксорт на Хаскеле в 2 строчки" не корректно - С.Х. - Цели и ограничения:
С++ это язык, а не законченная система.[...] По своему замыслу С++ - это лишь один язык среди многих. (4.2)
Не оставлять места языкам более низкого уровня, чем С++, исключая ассемблер (4.5)
С++ проектировался как язык для системного программирования и разработки приложений, в которых есть большой системный компонент. (7.4.2)
Если в компиляторы С++ не будет включён необязательный сборщик мусора, то в определенных областях С++ займёт невыгодные позиции, но я уверен, что такие компиляторы скоро появятся повсеместно. (9.3.2.2)
C++ не является идеальным инструментом для приложений, где не нужны развитые системные компоненты, а требования к быстродействию и потреблению памяти не слишком жёсткие. Однако при поддержке со стороны библиотек и, возможно, сборщика мусора, он может найти применение и здесь. (9.3.2.5) - Случаи из практики:
Во время опытной эксплуатации типобезопасной компоновки я пытался отслеживать результаты её работы. С помощью данного средства выявлялись необнаруженные ошибки в каждой из больших программ на С и С++, которые мы пытались откомпилировать и связать. (11.3.3)
В первоначальном проекте множественного наследования, который был представлен на Европейской конференции группы пользователей UNIX, состоявшейся в Хельсинки в мае 1987 г. [Stroustrup, 1987], фигурировало понятие делегирования [Agha, 1986]. [...] Реализация была тривиальной, затраты - минимальными. Поэтому данную идею испытало несколько пользователей. Много времени и сил здесь приложил Билл Хопкинс (Bill Hopkins). К сожалению, все пользователи, применявшие механизм делегирования, пострадали от серьёзных ошибок и путаницы. (12.7)
Странный синтаксис =0 был выбран вместо очевидной альтернативы ввести ключевое слово pure или abstract только потому, что тогда я не видел возможности добавить новое ключевое слово. Если бы я предлагал pure, то версия 2.0 вышла бы без абстрактных классов. (13.2.3) - Философское:
Если есть сомнения, нужно выбирать такое вариант средства, которому легче обучить. [...] Необходимо помнить, что, как уже говорилось программисты - неглупый народ; нельзя жертвовать важной функциональностью в угоду простоте. (4.4)
Правило нулевых издержек: чем не пользуетесь, за то не платите. [...] Виртуальные функции (см. раздел 3.5), множественное наследование (см. раздел 12.4.2), идентификация типов во время выполнения (см. раздел 14.2.2.2), обработка исключений и шаблоны - в каждом случае средство принималось лишь после того, как я убеждался, что его можно реализовать с нулевыми издержками. [...] Пожалуй именно данное правило заставило отказаться от включения в язык многих возможностей. (4.5)
По-моему, основным конкурентом С++ всегда был С. Сегодня С++ является наиболее распространённым объектно-ориентированным языком только потому, что это единственный язык, способный соперничать с С на его собственном поле и одновременно предоставлять существенные усовершенствования. (7.4.1)
Я считаю, что первоначальный вариант является классическим примером синтаксиса логичного, минимального и слишком лаконичного. Проблемы, которые возникали при изложении студентам темы инициализации базовых классов, полностью исчезли с появлением нового синтаксиса. (12.9)
Хорошие программы – это продукт хорошего образования, удачного проектирования, адекватного тестирования и т.д., а не наличия в языке средств, которые предположительно должны использоваться только «правильно». Употребить во вред можно любое средство, поэтому вопрос не в том, можно ли чем-то воспользоваться неправильно (можно!) или будут ли этим неправильно пользоваться (будут!). Вопрос в том, необходимо ли данное средство при условии его правильного употребления настолько, чтобы оправдать затраты на его реализацию, удастся ли смоделировать его с помощью других средств языка и реально ли с помощью обучения обратить во благо неправильное использование. (14.2.4)
Я подумывал о том, чтобы пойти дальше и разрешить наследование от встроенных типов и явное объявление для них встроенных операторов. Но сдержался. (15.11.3)
Главное, конечно, цели и ограничения. С++ не предназначен для того, чтобы на нём писать всё подряд, и Старуструп это понимал. Но на практике его мало кто слушал... Во всяком случае, на моей практике. Отступили от заветов :)
Чем сердце успокоилось
Мои основные претензии к С++ описаны здесь:
SH> Фокус в том, что правильно спроектировать библиотеку на C++ сложнее. ...
SH> Причина — С++ слишком заботится о байтах. О машинном представлении ...
Немного разверну.
В качестве "гарантированно переносимого" С++ предоставляет слишком низкоуровневые абстрации. Везде есть int, char, указатели. И, в общем, всё. Т.е., если библиотека хочет, чтобы её "понимали" все, она должна общаться с пользователем на языке, состоящем из int, char, указателей. Иначе это уже не просто библиотека, а, например, MFC-библиотека. Или ATL-библиотека. Или STL-библиотека. STL почти всем хороша, но её неудобно использовать из MFC-приложения..
Всё это усложняет совмещение нескольких библиотек, и/или фреймворков друг с другом. И написание "правильных" библиотек тоже усложняет.
Корни очевидны: широкий диапазон, нацеленность на системное программирование, прямую поддержку железа. Для подтверждения того, что подобные проблемы существуют и придуманы не мной - еще одна цитата из ДиЭС++:
Механизмы RTTI, которые предоставлялись разными библиотеками, были несовместимы между собой, и это стало препятствием для использования сразу нескольких библиотек. Кроме того, в каждом случае от проектировщика базовых классов требовалось многое предвидеть. Следовательно, был необходим какой-то механизм, который поддерживался бы самим языком (14.2)
Что будет
ДиЭС++ описывает период 1979 - 1994. 1998-й знаменит не только дефолтом, но и принятием стандарта С++, который, фактически, закрепил описанное в ДиЭС++ (ну и добавил кое-какие мелочи). Но на этом прогресс останавливаться не захотел, и через некоторое время комитет начал обсуждать следующую версию стандарта, названную C++0x. Подразумевалось, что стандарт выйдет где-то между 2001 и 2009 (и они ещё могут успеть! Хотя местами Страуструп шутит, что "X" не обязательно будет десятичной).
О будущем стандарте написана куча документов, текстов, есть мегабайты обсуждений в форумах, но я всё это не читал :) Я читал только Evolving a language in and for the real world: C++ 1991-2006 всё того же Страуструпа, ну и ещё кое что, о чём ниже. Несколько цитат:
- Дополнительно о периоде 1991-1998:
Reviewing this list in 2006, I’m struck by two design criteria (ideals) that are not explicitly stated:
• There is a direct mapping of C++ language constructs to hardware
• The standard library is specified and implemented in C++
Coming from a C background and being deep in the development of the C++98 standard (§3.1), these points (at the time, and earlier) seemed so obvious that I often failed to emphasize them.
The members of the J16 committee are volunteers who have to pay (about $800 a year) for the privilege of doing all the work.
Changing the definition of a widely used language is very different from simple design from first principles.Whenever we have a "good idea", however major or minor, we must remember that
• there are hundreds of millions of lines of code "out there" - most will not be rewritten however much gain might result from a rewrite
• there are millions of programmers "out there" - most won’t take out time to learn something new unless they consider it essential
• there are decade-old compilers still in use - many programmers can’t use a language feature that doesn’t compile on every platform they support
• there are many millions of outdated textbooks out there - many will still be in use in five years’ time
Basically, we (the members of the committee) desire change because we hold the optimistic view that better language features and better libraries lead to better code. Here, "better" means something like "more maintainable", "easier to read", "catches more errors", "faster", "smaller", "more portable", etc.
We agreed on many principles and details, but the size of the STL emerged as the major obstacle. There was no consensus about the need for large parts of the STL, there was a (realistic) worry that the committee wouldn’t have the time to properly review and more formally specify something that large, and people were simply daunted by the sheer number of things to understand, implement, document, teach, etc. Finally, at Alex’s urging, I took a pen and literally crossed out something like two thirds of all the text. For each facility, I challenged Alex and the other library experts to explain - very briefly - why it couldn’t be cut and why it would benefit most C++ programmers. It was a horrendous exercise. Alex later claimed that it broke his heart. --- Речь про того самого Александра Степанова - С.Х.
A common question over the years has been: Why don’t you add GC to C++? Often, the implication (or follow-up comment) is that the C++ committee must be a bunch of ignorant dinosaurs not to have done so already. --- В тексте есть довольно внятное объяснение "почему". И ещё более внятное - про отсутствие поддержки параллельности. Но они длинные, почитайте сами, раздел 5.5 - С.Х. - Про новенькое:
I first used the term "C++0x" in 2000 and started a discussion of "directions for C++0x" through presentations in the committee and elsewhere from 2001 onwards. By 2003, the committee again considered language extensions. The "extensions working group" was reconstituted as the "evolution working group". --- В комитете Страуструп возглавляет именно эту группу. - С.Х.
From many discussions and presentations, I have come with a brief summary of general aims and design rules for C++0x that appear to be widely accepted. Aims:
• Make C++ a better language for systems programming and library building - rather than providing specialized facilities for a particular sub-community (e.g. numeric computation or Windows-style application development)
• Make C++ easier to teach and learn - through increased uniformity, stronger guarantees, and facilities supportive of novices (there will always be more novices than experts)
As ever, there seems to be as many people claiming that the committee is spoiling the language by gratuitous complicated features as there are people who complain that the committee is killing the language by refusing to accept essential features.
В общем, очень познавательное чтение. Но, для того, чтобы понять, что же всё-таки войдёт в новый стандарт, его нужно немного дополнить.
Небезызвестный Герб Саттер мало того что работает в адской компании Майкрософт, так ещё и председательствует в комитете стандартизации С++. Просто страшно представить, сколько людей ежедневно посылают проклятия-и-пожелания в его адрес. Впрочем, человек он вроде хороший. Вот тут (01.11.2007) и тут (29.03.2008) он пишет про состоявшиеся заседания комитета. А тут даёт ссылку на документ State of C++ Evolution (Post-Bellevue 2008 Mailing) (Bellevue это город, где происходило заседание комитета в марте 2008), содержащий все принятые/ожидающие/отложенные и т.п. новшества (на текущий момент; следующее заседание в июле 2008, потом в сентябре 2008, следите за рекламой).
Подбивая бабки, по основным пунктам (тезисно, ориентируясь на Страуструпа, Саттера и заголовки документов, запарился читать все эти пропозлы, если честно; если где-то понял не так, буду благодарен за поправки):
- Много внимания уделено улучшениям шаблонов. Собираются (пока не приняты, но они очень стараются, правда) добавить понятие "концепции" (concept), позволяющее явно вводить ограничения на типы параметров шаблона. Уже приняты псевдонимы для шаблонов (насколько я понимаю, параметризованный typedef, но мне лень было разбираться). Шаблоны с переменным количеством аргументов (не вкурил пока, как это)... Ещё что-то куда-то туда же.
- Лямбда-функции. Гы :) Конечно, они получились "немного кастрированные" :) Если я не ошибся, то честных замыканий не получилось и вернуть лямбду в качестве результата работы функции нельзя. Ну, а чего ещё можно сделать в языке, который хранит локальные переменные в стеке. Но всё равно это немерянно круто, это расширяет использование всяких find_if и for_each до полного беспредела. Хотя это можно было и сейчас, т.е. это просто синтаксический сахар... Но сладенький :)
- Поддержка многопоточности делится между языком и библиотекой. Что куда я не понял :) Страуструп пишет, что язык поддержит TLS (ещё не принят) и атомарные операции (уже приняты, там вроде написано про библиотеку, не вникал). А библиотека реализует интерфейс к потокам в стиле Windows/POSIX (в каком-то виде уже принята, опять же не разбирался). Ну и ещё есть как минимум один связанный вопрос, про исключения в соединённых (joined) потоках (тоже принят).
- Сборки мусора, скорее всего, в этом стандарте не будет (но уже есть упоминания о C++1x).
- Куча мелких полезных улучшений. Вывод типа значения функции, например.. "Мелких" в том смысле, что они не меняют подход к программированию, но снимают некоторые мешающие ограничения или упрощают синтаксис.
Чем сердце успокоится
Стандарт C++0x неплохой. Я боялся, что ребята свихнулись, а они вполне ещё крепкие старики :) Кроме шуток, когда я услышал про многопоточность и сборку мусора, я подумал, что комитет попытается охватить в одном языке всё, что можно... И это будет абзац, потому что в результате язык нельзя будет применять нигде. Оказалось - нет. Выпрыгнуть из штанов С++ не пытается. И я этому очень рад.
Но, имхо, доля системного кода снижается, доля критичного по скорости кода снижается, доля кода, для которого надёжность и простота важнее производительности повышается... С++ не уйдёт, скорее всего, никогда (ну, никогда это в ближайшие 10 лет :)). В своей области он лучший. Но вот область эта уменьшается. И новый стандарт её не расширяет (к счастью!), он улучшает язык, но оставляет без изменения задачи, для которых он предназначен (т.е. которые разумно решать с его помошью).
Кстати, кто хочет посмотреть на живого Страуструпа - Лекция в CSSlub-е университета Waterloo, август 2007. Изложение избранных мест из Evolving a language in and for the real world: C++ 1991-2006 на час с небольшим, потом полчаса ответов на вопросы. Ответы интересные.