Герба Саттера (Herb Sutter) знает любой программист, пишущий на C++. Он автор книг, председатель комитета по стандартизации C++, а также архитектор языка программирования в Microsoft.
На C++ Russia 2020 Moscow Герб ответил на вопросы сообщества, заданные Анастасией Казаковой из JetBrains и Сергеем Федоровым из Яндекс.Лавки и поделился своими мыслями о С++20, стандартной библиотеке, концептах, синтаксическом сахаре и не только.
Мы перевели это интервью и теперь хотим поделиться с вами. Если хочется послушать интервью на английском — под катом есть также видеозапись.
О будущем С++
Анастасия Казакова: Как вы думаете, существует ли сегодня язык, который мог бы конкурировать с C++ или даже заменить его?
Герб Саттер: Вижу, у нас будет интересное интервью. Вы сразу задали вопрос, который напрямую затрагивает много очень важных проблем. Но так даже лучше.
Возможно, кто-то из вас видел новый доклад, с которым я выступал несколько месяцев тому назад на конференции Dev Around the Sun. В нём я перечислял качества, нужные новому продукту, в особенности языку программирования, чтобы быть успешным, и, в частности, там говорилось о возможных наследниках C++. Коль скоро это напрямую касается вашего вопроса, давайте сейчас посмотрим на слайд с этого доклада.
Любой продукт, во-первых, должен исправлять некоторый недостаток уже имеющегося продукта; в случае с C++ это, как правило, сложность языка и безопасность. Во-вторых, новый язык должен быть доступен везде, где доступен старый.
Этими двумя качествами обладает довольно много языков, потенциально способных заменить C++, к примеру, D, Rust и другие. Но помимо этих качеств я в докладе выделяю ещё и третье: совместимость. На примере перехода с Python 2 на 3, перехода на C99 и многих других случаев видно, что если у нового языка нет хорошей обратной совместимости с тем языком, который он пытается заменить, переход возможен, но он занимает где-то на десятилетие дольше. А если обратной совместимости изначально нет, то позже добавить её крайне трудно. Для D и Rust не смертелен тот факт, что они не могут напрямую совершать вызовы C++, но это существенно замедляет распространение этих языков.
А вот на грядущей конференции C++ Russia 2020 Piter, которая пройдёт c 11 по 14 ноября, будет интервью с Титусом Уинтерсом (Titus Winters) из Google: он расскажет о том, почему предлагает сломать обратную совместимость в С++.
Сейчас оба языка пытаются добавить обратную совместимость при помощи классов-оболочек и тому подобных вещей, так же, как Dart пытался добавить совместимость с JavaScript. Это сделать довольно сложно.
Для любого языка, конкурирующего с текущей версией C++, наиболее важным качеством является обратная совместимость. До сих пор этим качеством каждый раз обладала только следующая версия C++. То есть должна быть возможность параллельно использовать в проекте новый и старый код. В идеале даже одна строка нового кода, добавленного рядом со старым, должна давать полезный результат. Пока обеспечиваем это только мы в каждом новом стандарте C++. Надеюсь, нам это будет удаваться и в будущем.
Любому другому конкуренту C++ нужно будет уделить совместимости значительно больше внимания, чем это делается сейчас. Я не говорю, что другой язык вообще не может занять место C++ без обратной совместимости, просто это будет значительно более долгий процесс.
Сергей Фёдоров: Многие современные языки — Rust, Go, Python — развиваются значительно быстрее, чем C++. Как вы думаете, сможет ли C++ когда-либо достичь таких же темпов?
Герб: Думаю, следует сначала спросить себя: а желателен ли такой быстрый рост? C++, безусловно, эволюционирует значительно медленнее. Отчасти причина этого в том, что у него огромная пользовательская база, и от него зависят миллиарды строк кода в продуктах ведущих компаний практически всех отраслей. Мы не должны допускать нарушения работы этого кода.
В этом плане компании с небольшими пользовательскими базами могут позволить себе быть значительно гибче. Несмотря на это, мы всё равно развиваемся довольно быстро, в особенности в последние 10 лет. В этом году выйдет новый стандарт, в котором будет 4 крупных нововведения: концепты, модули, корутины и диапазоны. Они существенно изменят написание кода C++.
В общем, я считаю, что быстрое развитие далеко не всегда желательно. Во-первых, как я уже сказал, в случае с крупной экосистемой очень важно обеспечить совместимость. Приведу здесь аналогию: один и тот же поворот танкер выполнит значительно медленнее, чем лёгкое парусное судно.
Во-вторых, чтобы спланировать и добавить новую фичу, которая соответствовала бы духу языка и была бы принята сообществом, нужно много времени. В Microsoft я довольно много общаюсь с разработчиками C#. В последнее время они добавляют новые фичи примерно с такой же частотой, что и мы, поскольку они тоже стали большим и важным языком. Им тоже приходится быть разборчивыми и следить, чтобы нововведения действительно создавали ценность.
Вообще, по мере того, как растёт масштаб и сложность языка, острая необходимость в новых фичах постепенно спадает. Это не значит, что рост останавливается совсем, но значительно лучше становятся видны издержки добавления нового кода, в особенности если отсутствует хорошая интеграция с существующим кодом. Оказывается важно, чтобы язык не становился слишком большим. На мой взгляд, показательно, что в этой ситуации сейчас находится не только C++, но и языки вроде C#, которые точно так же стараются, с одной стороны, не добавлять лишнего, а с другой, сохранять достаточную гибкость для решения новых проблем.
О С++20
Анастасия: Коль скоро речь зашла об эволюции языка, давайте поговорим о C++20, в котором произошли, возможно, наиболее существенные изменения за последнее десятилетие. У нас появились модули, концепты, диапазоны и корутины; отдельное спасибо за оператор «космического корабля» (spaceship operator); появился std::format и многое другое.
Как комитет справился с таким крупным релизом? Были ли все эти изменения частью одного плана, или это случайность, что они совпали друг с другом?
Герб: Давайте взглянем на изображение с сайта isocpp.org.
Верхняя линия — это временной промежуток, когда Бьярне работал самостоятельно в 1980-е гг. Следующая линия соответствует первому этапу стандартизации. После этого был перерыв в несколько лет. Нижняя линия — это этап C++11. Как видно, во время этого периода мы стали вести работу в отдельных ветках, как в опенсорсном проекте. Когда работа над некоторой фичей завершается, соответствующая ветка объединяется с основным проектом.
На следующем изображении показана ситуация за последние 10 лет. Как видим, наши релизы выходят каждые три года: C++14, 17 и 20. Это можно сравнить с работой налаженной железнодорожной сети: поезд отправляется со станции строго по расписанию, и в него загружают весь груз, который есть на станции; если ваш груз до станции не успел — ничего страшного, отправите его со следующим составом.
У этой системы есть важное преимущество: мы всегда знаем, когда именно выйдет релиз. До этого могла быть такая ситуация, как с C++11: мы планировали потратить на него в два раза меньше времени, чем потребовалось в итоге. Поскольку тогда мы делали релизы в зависимости от готовности фич, срок выпуска каждый раз откладывался.
Теперь же выпуск происходит независимо от готовности, и это делает обстановку значительно менее напряжённой. Благодаря этому выросло качество каждого стандарта, качество фич, и мы к тому же стали успевать больше сделать. В общем, если вы взглянете на диаграмму, то увидите, что примерно ко времени C++17 так вышло, что у нас завершилась работа в нескольких важных ветках, и то же самое произошло с C++20.
Так что дело не в том, что мы за последние 3 года успели больше, чем раньше; просто подошла к концу работа одновременно над несколькими серьёзными фичами, каждая из которых заняла годы труда.
Анастасия: То есть нам просто повезло.
Герб: С одной стороны — повезло, с другой — хорошо, что нам не везёт так каждые три года. Сообщество просто не смогло бы поглощать новые фичи в таком темпе. Обстоятельства сложились так, что С++20 станет самым крупным релизом после С++11. Надеюсь, он окажет настолько же положительное влияние на сообщество.
Сергей: Как вы думаете, когда можно ожидать широкого распространения С++20 среди разработчиков?
Герб: Тут вопрос в том, что считать широким распространением. Ожидаем ли мы 90% распространения или 10%? В некоторых областях распространение идёт быстрее, чем в других. На встроенных системах обновление ПО происходит несколько медленнее, в том числе потому что у них на компиляторах много зависимостей, идущих вместе с операционной системой.
Но сейчас новые фичи C++ распространяются довольно быстро благодаря тому, что в компиляторах некоторые из этих фич уже реализованы, хотя новый стандарт ещё не вышел. Обычно же этот процесс занимает около пяти лет: для этого нужно, чтобы были созданы надёжные компиляторы с поддержкой всех фич и чтобы программисты научились ими пользоваться. Сейчас уже виден какой-то прогресс, но прежде чем нововведения станут использоваться большинством программистов, скорее всего, пройдёт несколько лет.
Анастасия: Я знаю, что фонд C++ (С++ Foundation) регулярно исследует распространение новых фич языка; в JetBrains мы также исследуем экосистему и сверяем с результатами, полученными фондом. По нашим данным, в этом году С++20 распространяется с огромной скоростью, его использует уже 12% экосистемы. Если же считать использование большинства фич C++20, то, согласно C++ Foundation, эта цифра ещё выше.
Довольны ли вы таким результатом? Или, по-вашему, можно было добиться ещё больших показателей?
Герб: Я вполне доволен. В разных отраслях темпы распространения разные, но, вообще говоря, двузначные показатели — отличный результат. В чём-то такая скорость даже неожиданная, но я думаю, что это свидетельствует о зрелости фич и о том, что они уже были много где реализованы, прежде чем вошли в стандарт.
В прошлом для С++ это далеко не всегда было так. Возможно, вы помните, что в первом стандарте, C++98, было несколько фич, которые не получили широкой реализации, а до возникновения полностью соответствующей стандарту реализации прошло пять лет.
Сейчас же у нас скорее всего будет несколько полных реализаций стандарта в компиляторах того же года, что и сам стандарт. Такого в истории нашего языка ещё не было. Это в значительной степени объясняется тем, что многие фичи были реализованы до того, как стали частью стандарта. Благодаря этому они не только оказались доступны значительно быстрее, но и качество фич возросло. Я очень рад, что разработчики компиляторов сейчас следят за нашей текущей работой и не ждут выхода стандарта.
Сергей: А вы лично довольны C++20?
Герб: Да. Для нас этот стандарт во многом стал рубежным. Давайте взглянем на слайд, который я показывал в прошлом году в комитете стандартов, почти тогда же, когда была годовщина высадки на Луну.
Как видим, этот релиз огромный. И важно, что мы не просто стараемся развивать язык, но и вносим изменения в стандартную библиотеку. В стандарте С++20 впервые за историю C++ язык включает все основные фичи, о которых Бьярне писал в 1994 году в книге «Дизайн и эволюция языка C++» (Design and Evolution of C++), когда мы только начинали работу над первым стандартом C++.
За всю историю языка было три масштабных релиза, добавивших сразу несколько важных фич; но версия C++20 — первая, целиком воплощающая видение Бьярне. Это очень важное событие, в особенности с учётом того, что Бьярне, к счастью, по-прежнему помогает нам со стандартизацией языка. У вас уже была возможность пообщаться с ним на этой конференции два дня назад.
Анастасия: Давайте теперь поговорим о предложениях по дальнейшему развитию языка. В каком состоянии сейчас находятся метаклассы? Как вы думаете, сколько нам ещё осталось их ждать?
Герб: Сразу признаюсь, что я подглядел в ваши вопросы перед интервью и решил, что это отличный способ обсудить текущее положение дел. У меня подготовлены заметки по этому вопросу, вы сейчас видите их на экране.
Где-то пять лет тому назад я попытался взглянуть на эволюцию C++ с высоты птичьего полёта и решить: что именно больше всего нужно языку в данный момент? Я хотел сформулировать общее направление развития, чтобы важные улучшения дополняли друг друга, а не возникали от случая к случаю. С тех пор я активно работал над рефлексией, мета-классами, легковесной обработкой исключений, «оператором космического корабля» и некоторыми другими инициативами. Я с самого начала задумывал их как составляющие единого курса C++ в сторону большей безопасности, удобства и программируемости.
Но комитету я их представлял по отдельности. Это было сделано, во-первых, чтобы не распыляться, и, во-вторых, чтобы убедиться, что каждая составляющая работает и является приемлемой для комитета. Одной из таких инициатив было правило Lifetime. Я начал выступать с докладами о нём в 2015 году. Это правила статического анализа для обнаружения случаев утечек и, в особенности, висячих указателей. Сейчас этот проект уже реализован в компиляторе Microsoft как расширение для статического анализа. Кроме того, он доступен в форке Clang, и постепенно его переносят в основной проект Clang, где он уже помогает находить баги в реальных проектах. Пока что для него написана только ознакомительная статья для WG21, но в будущем на его основе может быть сделано предложение.
С этим проектом связана другая фича. Сам я, скорее всего, не предложил бы её, но после выхода C++17 комитет по-прежнему интересовался сравнениями. Поскольку я уже работал над ними, я сделал предложение комитету, и, к счастью, они приняли его практически в неизменном виде, сейчас оно является частью C++ 20, чему я крайне рад. Было внесено два существенных улучшения: добавлена симметрия для равенства, чтобы не терять оптимизацию равенства, и сделаны мосты совместимости для существующих типов. На самом деле, я был удивлён тем, насколько быстро этот проект был принят. Несмотря на то, что были внесены некоторые изменения, в основном он сохранил первоначальную форму, а значит, он был правильно спланирован.
Давайте теперь поговорим о метаклассах, коль скоро ваш вопрос был в первую очередь о них. Для их реализации было необходимо три фундаментальных нововведения. Во-первых, программирование во время компиляции. На момент начала работы над метаклассами оно частично присутствовало в constexpr, но тогда оно было ещё сырое и не до конца обобщённое. Во-вторых, была необходима рефлексия, по которой тогда только-только появились первые предложения, и рассчитывать на неё было рискованно. В-третьих, нужна была генерация кода, создание исходного кода C++ во время компиляции — на тот момент в C++ этого ещё ни разу не делали.
Но при наличии этих трёх предпосылок метаклассы становятся просто синтаксическим сахаром, который во время компиляции применяет функцию рефлексии и генерации кода. Поэтому в первоначальной статье по метаклассам (P0707) также написано об этих трёх вещах: рефлексии, полном программировании во время компиляции, то есть возможности выполнять любой код C++ во время компиляции, и генерации кода C++; ничего этого на тот момент в языке не было.
Самым важным шагом в этом направлении стало добавление программирования во время компиляции. Это значит, что вторая предпосылка метаклассов в C++20 почти закончена. Функции consteval с гарантированным выполнением во время компиляции на самом деле были предложены именно в статье, которую я только что упомянул. На основе моей статьи Эндрю Саттон (Andrew Sutton) сделал реализацию метаклассов в Clang, с помощью которой были написаны consteval и некоторые другие фичи C++20.
В общем, с программированием во время компиляции дела обстоят хорошо. Что касается рефлексии, она входит в список семи приоритетов для C++23. Даже без учёта нарушений из-за COVID-19 я сомневаюсь, что рефлексию завершат к 2023 году, но ей точно будет уделяться много усилий. Это не может не радовать. Над генерацией сейчас тоже работают Дэвид Вандевурд и, опять-таки, Эндрю Саттон.
Когда рефлексия, consteval и генерация станут частью стандарта, для добавления метаклассов будет достаточно заявки на пяти страницах, в которой мы просто поблагодарим за реализацию этих трёх предпосылок, и предложим добавить поверх них синтаксический сахар, который позволит во времени компиляции применять функцию к классу. В общем, в этой области сделано уже очень многое, но, как видите, это проект, требующий много лет для завершения. Мне пришлось разбить его на несколько более мелких заявок, чтобы вся работа не была забракована из-за одного неудачного сегмента. Несмотря на это, мы всегда учитывали конечную цель — метаклассы; и мы всегда ориентировались на определённый вариант использования.
Легковесная обработка исключений — более новый проект, я впервые предложил её комитету в 2018 году. В отличие от метаклассов, на начальном этапе диалога прототипа ещё не было, и я хотел узнать, готов ли комитет вообще двигаться в этом направлении. С самого начала мы получили положительную реакцию, а также некоторые технические вопросы. В следующем году мы планируем начать работу над прототипом. Когда прототип будет готов и мы сможем ответить на эти технические вопросы, мы составим более подробную заявку.
Наконец, нужно сказать ещё об одном проекте, обсуждение которого началось только в феврале этого года. Это было в Праге на встрече юзер-группы, её запись выложена на YouTube. Речь идёт о передаче параметров и инициализации. Здесь используется подмножество правил статического анализа, которые использовались для Lifetime. Я уже подготовил об этом статью (под номером 708), но прежде чем подать её комитету, мне необходимо будет создать прототип.
Как видите, я сейчас работаю над несколькими проектами, каждый из которых требует нескольких лет работы. Правда, вы спрашивали меня только про метаклассы, но я получал вопросы и о других проектах, так что надеюсь, что этот обзор был вам интересен.
О Lifetime
Анастасия: Тогда давайте обсудим, как сейчас идут дела с Lifetime. Я так понимаю, что его реализация в компиляторе является ключевой для проекта, но заняты ей, если я не ошибаюсь, всего два разработчика. Их, конечно, можно только поблагодарить, но не замедлит ли недостаток ресурсов всю работу над этой крайне важной фичей?
Герб: Да, это возможно. Тут нужно помнить о двух вещах. Во-первых, речь идёт о двух реализациях. Первая является частью Visual Studio, она сделана командой статического анализа из Microsoft. Вторая — реализация Clang, и над ней действительно работает только два человека, Габор и Матиас. Но не стоит забывать, что у неё много пересечений с работой, проделанной Эндрю Саттоном и Уайеттом Чайлдерсом (Wyatt Childers). Эти правила доступны как часть компилятора cppx.godbolt.org. Во время моего последнего доклада по ним я демонстрировал их в составе этого компилятора.
Но самое главное, что всё это находится в форке Clang, а не в основном проекте. Как я уже говорил, некоторые из этих фич сейчас являются вышестоящими по отношению к Clang. Некоторые составляющие правил Lifetime сейчас поставляются вместе с компилятором Clang. Раньше всего работа была завершена над классификацией типов и над некоторыми расширениями существующих правил, которые уже были в реализациях Clang, и которые были обобщены в Lifetime. Они относятся к уровню оператора, то есть они довольно детальные.
Поскольку эти правила уже существуют и поскольку реализация правил Lifetime достаточно быстрая, чтобы её можно было запускать при каждой компиляции, эти правила включены по умолчанию. Поэтому теперь, когда, предположим, проект Fuchsia в Google получает новый компилятор Clang, они получают предупреждения Lifetime, при этом специально их не включая. Они уже исправили несколько багов в своём коде благодаря этим предупреждениям.
В общем, я хочу обратить ваше внимание на тот факт, что реализация прототипа уже в достаточной степени завершена и поэтому не требует много поддержки. Мы очень рады, что сообщество Clang заинтересовалось этой фичей, и благодарны за помощь тем, кто принимал предложения и запросы добавить эту фичу. Как я уже сказал, это реализация Clang; вместе с нашим продуктом также поставляется реализация от команды статического анализа Microsoft.
О концептах
Сергей: Давайте теперь поговорим о концептах. В Clang их реализацией занимался Саар Раз (Saar Raz), за что ему отдельное спасибо. Для распространения новых фич жизненно необходима поддержка компиляторами. Но выполняет эту работу очень часто всего один или два программиста. Как вам кажется, страдает ли C++ от недостатка усилий в этом направлении?
Герб: Когда мы говорим о реализации фич стандарта, чаще всего прототип действительно создаётся одним или двумя людьми, и назначение такого прототипа — показать жизнеспособность фичи. Например, в команде Visual C++ практически всю работу по «оператору космического корабля» проделал Кэмерон Дакамара (Cameron Dacamara) — передаю ему привет и благодарность. Но участвовала в работе вся команда (она состоит где-то из 150 человек), хоть сама реализация и была трудом только одного. Команда подтвердила бюджет, назначила задание, выполнила QA, сделала документацию, обеспечила пользовательскую поддержку и многое другое. Так что когда вы говорите о реализации какой-то фичи, необходимо иметь в виду целеполагание всей команды.
И нужно понимать, что когда авторы фичи заканчивают над ней работу, это не значит, что фича завершена; напротив, это не конец, а только начало. Дальше начинается работа над качеством, обратной совместимостью, обучением клиентов — последнее, кстати, требует очень много усилий. Если вы успешно прогнали юнит-тесты по своей фиче — это не конец работы, а только самое начало.
Но на этом начальном этапе действительно вполне может хватать усилий одного-двух человек. Некоторые фичи (например, модули) требуют больше труда. Над реализацией модулей в компиляторе C++ в разное время работали пять или шесть человек, и она ещё не закончена. В общем, не следует упускать из виду сознательных усилий команды в целом. Она продолжает обеспечивать поддержку и ресурсы в течение многих лет, когда работа над первоначальной реализацией уже давно завершена.
О статических исключениях
Анастасия: Давайте подробнее поговорим о статических исключениях. Как вы думаете, когда у нас появятся детерминистические исключения с нулевыми накладными расходами? Как будут эти исключения использоваться в стандартной библиотеке? Будет ли у нас две версии для каждой бросающей исключение функции?
Герб: Два года назад я пытался понять, готов ли комитет вообще двигаться в этом направлении. Я представил комитету гипотезу проблемы и гипотезу решения. Гипотезу проблемы комитет принял почти единогласно, то есть они согласились, что проблема есть. И было общее (хотя не единогласное) согласие попробовать предложенное мною решение. Это касалось трёх из четырёх основных частей моего предложения.
Кроме того, мне указали на некоторые технические вопросы, которые необходимо решить, чтобы обеспечить совместимость. Поскольку общее согласие сейчас есть, нужно приступать к работе над прототипом. Надеюсь, он будет завершён к следующему году. Я планирую сделать по меньшей мере одну, а, возможно, и две реализации статических исключений для ключевых коммерческих компиляторов.
Таким образом, будет доказано, что прототип решает поставленные задачи. Когда цель будет достигнута, мы снова начнём диалог с комитетом, и вопрос о стандартной библиотеке и обратной совместимости будем решать уже на этом этапе.
Что не вошло в С++20
Сергей: Как вы считаете, почему не удалось включить контракты в C++20?
Герб: Все понимают, что контракты очень нужны. Но работа над ними вначале потребовала определённого компромисса, а потом выяснилось, что этот компромисс многих на самом деле не устраивал, причём всех по-разному. В общем, фича ещё не созрела. А в нашей системе релизы выходят по расписанию, как поезда, независимо от готовности фич. Так что мы просто отправим её следующим составом.
Сейчас мы хотим без спешки правильно сформулировать требования к контрактам, чтобы они отвечали действительным потребностям программистов. Я знаю, что сейчас над контрактами ведётся очень активная работа, и я думаю, что она завершится если не к следующему стандарту, то точно к последующему.
Сергей: Почему в компиляторах C++ нет возможности отключить некоторые уровни? Например, из-за обратной совместимости очень многое из стандарта C++ убрать нельзя. Но если мне обратная совместимость не нужна, почему бы не отключить некоторые уровни компилятора? Планируется ли добавить такую возможность в будущем?
Герб: Отличный вопрос. Я об этом много думал на протяжении последних нескольких лет, и не я один. Я надеюсь, что в течение ближайших лет такая возможность появится.
Давайте вспомним об одном из ключевых преимуществ C++: принципе нулевых накладных расходов, сформулированном Бьярне Страуструпом. Обратите внимание, что нулевые накладные расходы — это не то же самое, что нулевые издержки. Задача не в том, чтобы фича не занимала ресурсов вообще, а в том, чтобы нельзя было сделать всё то же самое более эффективно вручную, не пользуясь предлагаемой абстракцией.
Кроме того, этот принцип означает, что если вы чем-то не пользуетесь, вы за это не платите. Принцип нулевых накладных расходов крайне важен, поскольку он делает абстракции C++ крайне эффективными. Правда, он кое-где нарушается, например, при обработке исключений — там используется затирание типов. Большую часть времени исключения не нужны, но мы все равно тратим на них ресурсы. И тем не менее, в целом C++ следует принципу нулевых накладных расходов довольно строго.
Вернёмся теперь к вашему вопросу. С определённой натяжкой принцип нулевых накладных расходов можно применить на уровне языка и совместимости. Как я уже говорил, обратная совместимость жизненно важна для распространения языка; но что, если её можно обеспечить так, чтобы не тратить на неё ресурсы, когда она не используется? И если в файле исходного кода нам не нужно выполнить `#include какого-нибудь заголовка 40-летней давности, то не можем ли мы упростить используемый там вариант языка? Я много об этом думал и надеюсь, что в ближайшие несколько лет у нас появится такая возможность. Как минимум, это полезный ход
О стандартной библиотеке
Анастасия: Давайте теперь обсудим стандартную библиотеку. Вполне естественно, что по мере развития языка она растёт, в ней появляются новые типы и новые функции. Но сейчас, как мне кажется, комитет пытается включить в неё всё на свете. Это затрудняет её для восприятия как новичкам, так и людям, работавшим с ней годами. Быть может, некоторые функции, не относящиеся к жизненно важным, стоит выделить в отдельные библиотеки?
Герб: В 2012 году в докладе на GoingNative я сравнивал размер стандартной библиотеки в C++, .NET и Java, и разница получилась в несколько порядков. Нам по-прежнему далеко в этом плане до этих языков. Так что я не думаю, что стоит переживать из-за чрезмерно большого размера стандартной библиотеки.
Больше того, нам в неё хорошо бы ещё включить вещи вроде JSON и HTTP. Так что хотя в последнее время в неё добавляется много важных вещей, нам ещё есть куда расти. Я не думаю, что нам стоит наращивать стандартную библиотеку до размеров Java или .NET. Сейчас они сожалеют о том, что так раздули свои стандартные библиотеки, поскольку это требует дополнительных ресурсов и усложняет обучение языку. И всё же наша библиотека ещё слишком маленькая.
Правда, нужно сказать, что в C++ только сейчас налаживается управление пакетами. К счастью, мы постепенно отходим от той ситуации, когда новые библиотеки ищутся через Google, и каждую стороннюю библиотеку приходится устанавливать своим способом. Сейчас у нас есть инструменты вроде vcpkg, conan и прочих. Конечно, они сильно уступают apt-get или Cargo, но они существенно лучше того, что было лет пять тому назад, и они продолжают совершенствоваться.
Когда в сообществе есть хорошо известный набор библиотек и простой способ доступа к ним, можно не запихивать так много всего в стандартную библиотеку. Так что я считаю, что стандартная библиотека ещё не полная, но мы можем не только наращивать эту библиотеку, но и совершенствовать управление пакетами для библиотек C++. Отчасти с этим помогают модули, поскольку они позволяют избавиться от модели `#include, унаследованной нами от C. В общем, я надеюсь, что в будущем в этой области мы будем продолжать наблюдать улучшения.
О модификаторе noexcept
Сергей: Что вы думаете о модификаторе noexcept
, в частности, о его накладных расходах и размере бинарника?
Герб: Мне очень нравится noexcept
. Правда, его, как и большинство модификаторов C++, следовало бы сделать включённым по умолчанию. То есть должен быть не noexcept
, а not noexcept
, согласие на throws
. Сейчас это сделать невозможно из-за проблем с обратной совместимостью и в целом из-за наследия языка.
В моей статье P709 об исключениях на основе значений (value-based exceptions) я, помимо прочего, говорю о согласии на throws
. Так что мы потихоньку начинаем идти к ситуации, когда большинство функций являются noexcept
. Накладные расходы, о которых вы говорите, возникают из-за того, что функции noexcept
требуется проверить, возвращает ли функция исключение при вызове terminate
. Это требует создать ветку в генерируемом коде.
Но мне кажется, что эти издержки сильно преувеличены. Измерения накладных расходов, связанных с этой операцией, как мне кажется, неполны. С одной стороны — да, для функции приходится генерировать больше кода, и эти затраты действительно можно измерить. С другой, noexcept
позволяет оптимизировать сами вызовы функций, и последние исследования, принимающие во внимание эти оптимизации, показывают, что noexcept
на самом деле делает бинарники быстрее. Сейчас в этом направлении ведутся исследования.
Преимущества такого подхода по-настоящему станут видны только в будущем, когда большинство функций станут noexcept
. Пока нам до этого далеко. Но даже сейчас noexcept
чаще всего делает код быстрее. В общем, измерять нужно не только издержки вызова отдельной функции, но и издержки на более высоком уровне.
О const
Анастасия: У нас ещё один практический вопрос. Как нам добиться принудительной транзитивности const
? Например, есть примеры, когда вызов с const
изменяет объект. Может ли язык каким-либо образом запретить вызов неконстантных элементов функций?
Герб: Тут возможны две разных ситуации: const_cast
и глубокая константа. Бывает, что вызываешь некую функцию, которая принимает ссылку const
, а она преобразует константу в изменяемое значение и начинает с ним орудовать — так делать не надо. В C++ Core Guideline можно включить правило, которое не позволяет компилировать такой код. Это небезопасный код, как reinterpret_cast
, который позволяет шуровать в битах. Так что в случае с const_cast
я бы сказал, что этого просто не стоит делать.
Более интересно дело обстоит с глубокой константой. Здесь я не могу дать однозначного ответа, поскольку досконально этот вопрос я не изучал. Зато я знаю, что те, кто изучали, не нашли пока способа создать глубокую константу, не касаясь более общего вопроса неизменяемости.
Эта проблема тесно связана с другими вопросами неизменяемости, в частности, с «заморозкой» дерева изменяемых объектов, то есть превращения их в неизменяемые. Глубокая константа — это граф изначально неизменяемых или «замороженных» объектов, и с таким форматом могут работать компиляторы и оптимизаторы. Так что я думаю, что эта область в будущем будет активно развиваться.
Что касается квалификаторов глубоких констант, которые позволяют считать объект константой на определённом участке кода, хотя в других участках этот объект изменяемый, я не знаю о каких-либо существенных наработках в этой области. Но что касается настоящей неизменяемости, это очень перспективное направление, и в других языках она отлично себя зарекомендовала.
Об обучении С++
Сергей: У меня есть вопрос относительно обучения C++. Скотт Майер больше не занимается преподаванием C++; какие книги вы порекомендовали бы по современному C++?
Герб: Есть несколько хороших авторов — Николай Йосуттис (Nicolai Josuttis), Райнер Гримм (Rainer Grimm); обязательно прочитайте второе издание книги Бьярне Страуструпа «Язык программирования C++. Краткий курс» (A Tour of C++), оно постоянно обновляется, чтобы соответствовать наиболее позднему стандарту C++. Можете спросить Бьярне, как обстоят дела с третьим изданием — там будет про C++20. Больше мне сейчас ничего не приходит в голову, но я уверен, что есть и другие хорошие книги — заранее приношу свои изменения, если я кого-то забыл.
Кстати, авторы, которых упоминает Герб, выступали на C++ Russia. Ссылки на видео представлены ниже.
Nicolai Josuttis — C++17 — the biggest traps
Rainer Grimm — Concurrency and parallelism in C++17 and C++20/23
Bjarne Stroustrup — Interview and Q&A with Bjarne Stroustrup
Анастасия: У нашей аудитории есть вопрос о вероятностном программировании. Если вы знакомы с этим понятием, скажите, можно ли его применить к C++? Я знаю, что несколько лет назад в одном интервью об этом говорил Эрик Липперт (Eric Lippert).
Герб: Я слышал об этом подходе, но недостаточно хорошо его знаю, чтобы сказать что-либо по существу.
О работе во время пандемии
Сергей: Скажите, как повлиял на работу комитета COVID?
Герб: Само собой, мы перестали проводить встречи вживую, и не будем их проводить, пока это не станет безопасно. Сейчас работа комитета идёт в форме телеконференций в подгруппах. Мы стали переходить к этому формату после встречи в Праге. В частности, телеконференции стали проводить две основных группы проектирования: группа проектирования эволюции языка (language evolution design group) и группа проектирования эволюции библиотек (library evolution design group), до этого они таким форматом ещё не пользовались. Эти группы проводят встречи каждую неделю и обсуждают заявки.
Сейчас мы будем пытаться перевести в удалённый формат принятие решений по предложениям и по включению их в язык и в черновой вариант стандарта C++23. До сих пор это делалось только в формате живой встречи, но в этом году мы планируем перейти на удалённую форму.
В общем, мы сейчас все в одной лодке. Безопасность превыше всего, и, судя по новостям, точно предсказать, как будут развиваться события, мы не можем. Однозначно можно сказать только одно: пока встречаться нельзя, мы встречаться не будем. Тут важны соображения и законности, и, в особенности, безопасности.
Последнее, чего бы нам хотелось — это чтобы люди чувствовали себя обязанными посещать наши встречи в ущерб своей безопасности. Никакая техническая работа не важнее нашего здоровья. Как бы мы ни любили C++, своих близких и свои сообщества мы любим больше. Так что я думаю, что здесь важна правильная расстановка приоритетов. К тому же, оказалось, что Teams, Zoom (ISO предоставляет нам всем аккаунт в ZOOM), Google Meet и подобные программы крайне продуктивны. На самом деле, мы и до этого постепенно их осваивали, просто обстоятельства заставили нас значительно раньше и значительно настойчивее двинуться в этом направлении. Мы никогда не работали в онлайне столько, сколько за последние три месяца. Посмотрим, как будет меняться обстановка.
Анастасия: Спасибо. Видимо, мы скоро увидим плоды вашей работы в онлайне. Чем сейчас в основном занят комитет? Подготовкой C++23, или отладкой C++20?
Герб: И тем, и другим, но в основном C++23. На самом деле, мы уже несколько лет работаем над C++23, поскольку мы заранее знали, что некоторые фичи не удастся включить в C++20, и, как я уже говорил, если мы не успеваем к дате релиза, то мы переносим фичу на следующий релиз. И всё же по мере приближения даты релиза соотношение работы над старым стандартом и новым меняется; а сейчас работа над C++20 уже почти завершена. То есть стандарт уже фиксирован, мы заканчиваем последние бюрократические формальности с ним. Но, как и любой продукт, он будет требовать отладки. Чаще всего исправления просто откладываются до следующего стандарта, но иногда отладку багов включают в старый стандарт постфактум. Тем не менее наши усилия в основном сконцентрированы на C++23, рефлексии, TS и прочих вещах, выходящих за рамки C++20.
Об ISO и C++
Сергей: Так ли необходим ISO для C++? Стандартизация в рамках ISO накладывает множество ограничений: непрозрачность процесса, ограничения на бесплатную публикацию стандарта C++ и многое другое.
Герб: Это ограничения действительно существуют, но здесь важен баланс. На встречах по стандартам собираются представители ведущих коммерческих организаций, занимающихся разработкой инструментов C++ и использующих этот язык, и совместно определяют траекторию развития языка. Если бы это происходило не в рамках организации по стандартизации, то это характеризовалось бы как сговор, такие встречи запрещены антимонопольным законодательством. В рамках этого законодательства разрешено договариваться только о стандартах.
Поэтому на наших встречах нам нельзя обсуждать сбыт, цены и тому подобные вещи. Мы постоянно напоминаем, что говорить можно только о технической стороне дела. Так что если бы мы не входили в ISO, нам нужна была бы другая организация по разработке стандартов (Standard Development Organization, SDO) или организация по установлению стандартов (Standard Setting Organization, SSO), чтобы было понятно, что мы честные люди и не занимаемся сговором. Тот факт, что мы состоим в ISO, делает нашу деятельность прозрачной, и подтверждает, что наши намерения вполне легальны и направлены на благо сообщества. Правда, тем же целям служит и создание опенсорсного проекта. Но в нашем случае очень важен тот факт, что в рамках организации сотрудничает множество коммерческих разработчиков.
Нужно также заметить, что ISO значительно менее закрытая, чем это принято считать, в особенности в случае C++. Формально согласно правилам ISO на встречах не могут присутствовать люди, не входящие в организацию ISO. Но при этом организатор (то есть я) может приглашать сторонних экспертов, что я всё время и делаю.
Кроме того, на нас распространяются не только правила ISO, но и правила собраний по стандартам US Insights. Благодаря тому, что мы действуем в рамках двух наборов правил, мы можем делать многое, что было бы запрещено в рамках только одного набора правил, например, приглашение наблюдателей. На каждом собрании по стандартам у нас присутствуют люди, не состоящие в нашей организации и не платящие взносов, причём чем дальше, тем их больше.
Но ISO так или иначе всё равно зарабатывает, один из способов заключается в том, что участниками организации становятся страны, и они платят деньги из бюджета. Несмотря на это, черновики статей по стандартам и предложениям всегда находятся в открытом доступе, хоть это и не касается конечных версий текстов публикуемых стандартов. С учётом всего этого я считаю, что мы настолько открыты, насколько возможно. На нашем сайте, isocpp.org, а также на сайте open-std.org можно найти статьи по предложениям, когда-либо опубликованные нашей организацией. Надеюсь, они вам будут полезны. И мы ищем способы добиться ещё большей прозрачности. Так или иначе, без ISO нам не обойтись.
О работе Numerics
Анастасия: Почему многие группы в комитете C++ сейчас неактивны, например, исследовательская группа SG6 Numerics?
Герб: Numerics вполне активна. Действительно, есть группы, в которых сейчас ничего не делается — например, SG11 Databases. Но большинство всё-таки активны, сейчас у нас 23 действующих подгруппы, и большинство из них — исследовательские группы.
А неактивны в основном те группы, которые уже завершили свою работу. Например, в течение некоторого времени не функционировала подгруппа Modules, потому что её работа перешла в основные подгруппы. Но с тех пор мы решили, что с модулями мы ещё не закончили, и поэтому группа была снова открыта, сейчас ей руководит Дэвид Стоун (David Stone).
Сейчас закрыта группа по концептам, не потому что концепты потеряли свою значимость, а потому, что работа над ними закончена. Исследовательские группы — это своего рода инкубаторы, поэтому когда фича попадает в черновой вариант основного стандарта, группа прекращает свою работу, инкубация закончена. Но SG6 по-прежнему активна, они сейчас работают над Numerics TS. Если интересно, можете написать Лизе Липпенкотт (Lisa Lippincott), она руководит этой группой и находится в курсе последних событий.
Сергей: Стоит ли нам ожидать техническую спецификацию по Numerics в ближайшем будущем?
Герб: Насколько я знаю, над ней сейчас идёт работа, но я не могу сказать, скоро ли появится черновой вариант спецификации.
О фонде С++
Анастасия: Давайте поговорим о фонде C++ (C++ Foundation). На его сайте написано, что это некоммерческая организация, основной целью которой является поддержка сообщества C++, а также способствование использованию и обучению языку. Чем именно занимается эта организация? Как она поддерживает сообщество?
Герб: Больше всего средств фонда уходит на проведение CppCon. Мы каждый год организуем профессиональную видеосъёмку докладов и бесплатно предоставляем записи сообществу. Таким образом мы стараемся не только обеспечивать высококачественные материалы, но и задавать стандарт для всех конференций по C++. Мы очень рады, что на многих конференциях, в том числе на вашей и на ACCU, тоже стали вести профессиональную видеосъёмку. До появления CppCon её было значительно меньше.
Помимо этого, мы предоставляем гранты для написания предложений по стандартам. Есть предложения, по которым работу смогли провести только благодаря нашим грантам; без них не было бы выполнено несколько фич в C++20, хоть мы и стараемся их не афишировать. У авторов просто не было бы возможности продолжить работу над ними.
Комитет оценил значимость фич и способствовал их завершению. Фонд не выбирает, какие именно предложения будут реализованы; он предоставляет финансирование, а участники комитета сообщают нам об одобренных предложениях, которые не могут быть завершены без дополнительных средств. В таких случаях составляется заявка на грант, и до сих пор нам удалось удовлетворить почти все заявки. Очень важно, что решения по стандартизации принимает не фонд, а комитет. Мы лишь помогаем комитету.
Другая форма помощи, которую предоставляет фонд — оплата стоимости посещения встреч для людей, которые иначе не смогли бы на них попасть. Это не случайные посетители, а те, у кого есть предложения в подгруппах, и которым для реализации предложения обязательно нужно присутствовать на встрече, но по какой-либо причине они не могут себе позволить приехать.
Наконец, в течение последних пяти лет значительная часть встреч целиком или частично оплачивалась фондом. Вот те инструменты, при помощи которых мы стараемся помочь комитету; мы не диктуем свою политику, а помогаем комитету добиться его целей.
Я говорю «мы», потому что я одновременно заседаю и в C++ Standards Committee, и в Standard C++ Foundation. Но деятельность фонда помогает всем участникам комитета, в этой роли я не имею права выбирать, на что тратятся средства. Все директора, включая меня, Майкла Вонга (Michael Wong), Чендлера Каррута (Chandler Carruth), Роджера Орра (Roger Orr) и Бьярне Страуструпа, убеждены, что мы не должны решать, на что идут гранты, хоть мы и играем важную роль в составлении стандарта ISO.
На сайте isocpp.org в разделе «О нас» (About) изложена наша политика грантов, и там специально указано, что директора не имеют голоса в вопросе о том, кому предоставляются гранты; мы выполняем лишь роль администраторов, предоставляющих эти средства. Решения о финансировании принимаются руководителями подгрупп, которых сейчас 23.
О синтаксическом сахаре в С++
Сергей: Ещё один короткий вопрос. Как вы считаете, стоит ли добавлять в C++ синтаксический сахар вроде лямбд и диапазонов? Не увеличивает ли он сложность языка?
Герб: Да, это возможно. Вопрос действительно короткий, поэтому ответить я тоже постараюсь коротко. Сахар хорош в том случае, если он делает доступными решения, которые без него нельзя было бы сделать.
В случае с лямбдами мы можем написать те же объекты функций от руки, лямбда здесь действительно просто синтаксический сахар. Но она даёт очевидную ценность, которой иначе не было бы, и код становится более лаконичным и выразительным. Нужно избегать ситуации, когда мы можем одно и то же написать двумя различными способами.
Формально так дело обстоит и с лямбдами, но на самом деле мы не могли бы использовать написанные от руки объекты так же, как и лямбды, потому что без них во время выполнения создавать объекты функций в выражениях невозможно. Сахар не должен создавать возможность написать одно и то же двумя разными способами, в каждом случае с разным набором аргументов и параметров. В общем, с сахаром главное не перестараться.
Об игре на фортепиано
Анастасия: Спасибо, Герб. Наше интервью подходит к концу, и напоследок я хотела бы спросить: как ваши успехи в освоении фортепиано? Вас было очень здорово слушать на CppCon.
Герб: Спасибо большое, благодарю за терпимость к ошибкам во время исполнения. Я сейчас играю дома, поскольку у нас карантин начался даже раньше, чем в Сиэттле, который ввёл у себя карантин одним из первых в США. Так что за эти месяцы у меня было время, чтобы попрактиковаться. Но для меня гораздо важнее не играть самому, а организовать «свободное пианино» на CppCon, чтобы послушать, как играют другие. Мне всегда хотелось, чтобы на CppCon была такая культурная атмосфера, и я очень рад тому, что она у нас есть. Сам я тоже два или три раза за конференцию играю на этом свободном пианино, но мне гораздо интереснее слушать других людей, причём не только с нашей конференции. В прошлом году мы проводили встречу, которая была в одном здании со встречей полицейских и пожарников. В общем пространстве стояло пианино, и на нём много раз играли люди в униформе. Мне очень понравился этот опыт.
Это интервью с июньской конференции — а сейчас мы вовсю готовим следующую C++ Russia, которая пройдёт 11-14 ноября в онлайне. Там тоже будут интервью с интересными людьми: с Мэттом Годболтом — о его проекте Compiler Explorer, с Титусом Уинтерсом — о его предложении сломать обратную совместимость. А кроме этого, будут 20 докладов, связанных с C++. Так что, если это интервью оказалось для вас интересным, там тоже наверняка найдётся интересный контент для вас. Полная программа доступна на сайте конференции, билеты — там же.
Автор: Olga Kuznetsova