Сейчас ведётся много споров и дискуссий о будущем C++.
Не только на Reddit и одном оранжевом веб-сайте, но и совершенно точно на официальных заседаниях комитета по стандарту C++.
Абсолютное состояние (языка C++)
Похоже, мы находимся в следующей ситуации:
-
Evolution Working Group (EWG) языка C++ как раз достигла консенсуса по внедрению P3466 R0 - (Re)affirm design principles for future C++ evolution:
-
Это означает отсутствие поломок ABI, сохранение совместимости компоновки с кодом на C и предыдущими версиями C++.
-
Также это означает отсутствие «виральных аннотаций» (например, аннотаций времени жизни)1.
-
Удвоение усилий по множеству несовместимых задач, например, отсутствия поломок ABI и принципа zero overhead2.
-
Плохо это или хорошо, но это (в буквальном смысле) удвоение усилий по развитию текущей траектории языка C++.
-
1. Если быть циничным, то это можно интерпретировать как явное «не одобряем» в отношении аннотаций времени жизни Rust и предложения Safe C++ Шона Бакстера. Если же умерить цинизм, то это, по крайней мере, трезвое осознание того факта, что отрасль не хочет заниматься рефакторингом старого кода.
2. «Мы не платим за то, чем не пользуемся». По сути, старая фича C++ может повлиять на производительность среды исполнения, только если вы активно её используете. Это не совсем совместимо со стабильным ABI, потому что стабильный ABI (понимаемый как фича C++) исключает определённые улучшения производительности.
Тем же временем:
-
Правительство США хочет, чтобы люди перестали пользоваться C++:
-
Агентство по кибербезопасности и защите инфраструктуры (CISA)
-
Всё именно так: различные ветви правительства США выпустили статьи, отчёты и рекомендации, чтобы предупредить отрасль о нежелательности использования небезопасных по памяти языков.
-
-
Всевозможные крупные технологические игроки осваивают Rust:
-
Microsoft переписывает базовые библиотеки на Rust.
-
Google, похоже, приняла решение о переходе на Rust и начала работу над инструментом для обеспечения двунаправленной функциональной совместимости между C++ и Rust.
-
AWS использует Rust.
-
и так далее.
-
-
Кстати, о больших технологических компаниях: а вы заметили, что Херб Саттер уходит из Microsoft, а MSVC, похоже, не торопится реализовывать фичи C++23 и просит сообщество о расстановке приоритетов.
-
Произошло печально известное пражское голосование по ABI (если вкратце: «C23 не поломает ABI, и непонятно, будет ли это когда-либо сделано»). Google, предположительно, существенно снизила уровень своего участия в процессе разработки C, и вместо этого начала работать над собственным языком-потомком C++. Компания даже выпустила сводку с перечислением всех проблем, которые у неё возникали при попытках улучшения C++3.
-
В сообществе ходят уже всем известные истории людей, изо всех сил старавшихся участвовать в процессах комитета по стандарту: их просто пережёвывали и выплёвывали.
-
Модули по-прежнему не реализованы. Мы уже модули?4
-
«Профили безопасности» всё ещё находятся в странном состоянии и у них нет готовой реализации; есть попытки добавить определённую долю безопасности в уже написанный код на C++ с минимизацией изменений в этом коде. Сам Шон Бакстер занял позицию против профилей и сказал, что C++ «недостаточно покрыт спецификациями».
3. Думаю, Carbon гораздо интереснее, чем его воспринимает большинство. Возможно, я как-нибудь напишу об этом пост.
4. Мы к этому идём! Похоже, буквально за несколько дней до публикации статьи в GCC добавили поддержку модуля std
. Это может занять длительное время, и кто знает, какой будет экосистема, но это уже прогресс!
Не знаю, как вы, но если бы я смотрел на всё это, как внешний наблюдатель, то мне бы определённо казалось, что C++, по сути, разваливается на куски, и что большое количество людей потеряло веру в способность комитета по C++ каким-нибудь образом решить все эти проблемы5.
5. Разваливается на куски сейчас? Ну, это зависит от того, что иметь в виду. Весь этот код на C++ никуда не денется. То есть в этом смысле нет. Код на C++, по крайней мере, продолжит существовать.
Две культуры
Похоже, люди ищут другие решения.
Возьмём Google. Эта компания, очевидно, навсегда потеряла веру во «всемогущий процесс» с момента голосования по ABI. Это не потеря веры в сам язык, Google обладает одной из крупнейших в мире кодовых баз на C++, и она послужила компании отличную службу. Это потеря веры в способность языка эволюционировать в условиях нарастания давления с разных сторон (потенциальные правительственные постановления, языки-конкуренты, потребность у основных игроков в повышении производительности и гарантиях безопасности и так далее).
Так в чём же проблема? Почему C++ просто... не меняется?
Ну, понять это легко. Достаточно прочитать то, что написал Херб Саттер в своей статье о профилях:
«Мы должны минимизировать потребность в изменении готового кода. Десятки лет опыта показали, что большинство пользователей с большими кодовыми базами не могут и не будут менять даже 1% строк кода, чтобы он соответствовал правилам строгости, даже из соображений безопасности, только если их не заставят это сделать правительственные требования», — Херб Саттер.
Круто. Кого-то это удивило? Не думаю.
Для контраста приведём биографию Чендлера Каррета со страницы члена WG21:
Я руководил проектированием инструментария и систем автоматизированного рефакторинга C++, построенных на основе Clang и в дальнейшем ставших частью проекта Clang. […]
В Google я руководил проектом по масштабированию инструментов автоматизированного рефакторинга на основе Clang до объёма всей нашей кодовой базы (более ста миллионов строк кода на C++). Мы можем анализировать и применять рефакторинги во всей кодовой базе всего за двадцать минут.
Заметили что-нибудь? (Конечно, заметили, я это специально выделил.)
«Автоматизированный инструментарий». Только ведь дело не ограничивается лишь им, это лишь один яркий пример.
По сути, мы видим конфликт между двумя разительно различающимися лагерями пользователей C++:
-
Относительно современные способные технологические корпорации, осознающие, что их код — это ценное имущество. (Здесь можно не ограничиваться только big tech. Любой вменяемый C++-стартап тоже относится к этой категории.)
-
Все остальные. Любая древняя корпорация, в которой люди до сих пор спорят о том, как расставлять отступы в коде, а один молодой инженер умоляет своё руководство позволить ему настроить линтер.
Одна из этих групп будет способна справиться с миграцией практически беспроблемно, и это та группа, которая способна создать свой стек C++ на основе исходников с версионностью, а не та группа, которая по-прежнему использует готовые библиотеки из 1998 года.
Эта способность создания целого стека зависимостей на основе исходников с версионностью (предпочтительно с автоматизированными тестами) — вероятно, самая важная разделительная линия между двумя лагерями.
Разумеется, на практике это градиент. Могу только представить, сколько пота, крови, денег и труда потребовалось, чтобы превратить кодовые базы компаний big tech из ужасающих кусков грязи в относительно управляемые, собираемые, чуть менее пугающие куски грязи с надлежащим контролем версий.
Обладая послезнанием, легко подумать, что всё это было неизбежно: что существует чёткое разделением между потребностями корпораций наподобие Google (которые используют относительно современный C++, имеют автоматизированный инструментарий и тестирование, а также современную инфраструктуру) и желанием (очень сильным) обратной совместимости.
Если смотреть трезвым взглядом, то окажется, что идея единого, свободного от диалектов и унифицированного C++, похоже, мертва уже многие годы6. У нас есть как минимум две основных разновидности C++:
-
Любой хотя бы отдалённо современный C++. Всё, что можно собрать из исходников с версионностью при помощи специального чистого и унифицированного процесса сборки, который хотя бы немного сложнее, чем сырой CMake, и который хотя бы с натяжкой можно назвать работающим. Добавить какие-нибудь статические анализаторы, форматировщик, линтер. Любой стандарт обеспечения чистоты и современности кодовой базы. Вероятно, хотя бы C++17, с
unique_ptr
,constexpr
, лямбдами,optional
, но смысл не в этом. Самое главное — это инструментарий. -
Легаси-C++. Всё, что не является первым пунктом. Любой C++, который хранится в древних запылённых серверах банка средних размеров. Любой C++, который зависит от ужасно устаревшего куска скомпилированного кода с утерянными исходниками. Любой C++, который развёрнут на pet-сервере; чтобы развернуть его где-то ещё одному инженеру потребуется целый месяц, чтобы хотя бы разобраться во всех его косвенных зависимостях, конфигурациях и переменных окружения. Любая кодовая база, которая считается местом возникновения затрат. Любой код, в котором сборка любого используемого двоичного файла из исходников требует чего-то большего, чем нажатие на несколько кнопок, а то и вовсе невозможна.
6. Жила ли она вообще когда-нибудь, с этими всевозможными компиляторами и их собственными расширениями — это уже другой вопрос.
Как вы, наверно, заметили, главное различие заключается вообще не в самом C++. Разница заключается в инструментарии и в способности выполнять сборку из исходников с версионностью чистым, чётко определённым образом. В идеале даже в способности развёртывать код без необходимости запоминать тот один флаг или переменную окружения, которую обычно добавлял предыдущий разработчик, чтобы всё не поломалось.
То, насколько кодовая база Google соблюдает идиомы «современного» C++, вторично по сравнению с качеством инструментария и того, можно ли собирать код из исходников.
Многие скажут, что инструментарий — это не сфера ответственности комитета по стандарту C++, и они будут правы. Инструментарий — не сфера ответственности комитета по стандарту C++, потому что комитет отрекается от любой ответственности за него (он сосредоточил усилия на спецификациях языка C++, а не на конкретных реализациях)7. Это сделано с умыслом, и их сложно винить, учитывая багаж легаси. C++ — это стандарт, унифицирующий разные реализации.
7. Впрочем, это немного несправедливо. Существует исследовательская группа SG15, занимающаяся инструментарием. См. например, этот пост. Разумеется, весь процесс по-прежнему сосредоточен на написании статей, а не, например, на выпуске канонического менеджера пакетов.
Тем не менее, если уж язык Go и сделал что-то правильно, так это упор на инструменты. По сравнению с ним C++ находится в доисторической эпохе, когда ещё не изобрели линтеры. C++ не имеет унифицированной системы сборки, у него нет ничего даже близко похожего на унифицированную систему управления пакетами, его невероятно сложно парсить и анализировать (а это ужасно мешает инструментарию) и он ведёт пугающе неравный бой с законом Хайрама по поводу каждого изменения, которое нужно внести.
Между двумя лагерями есть огромная разрастающаяся пропасть (хороший инструментарий, беспроблемная сборка из исходников против плохого инструментария и невозможности сборки из исходников); честно говоря, я не вижу никаких подвижек к уничтожению этой пропасти в обозримом будущем.
Комитет по C++ изо всех сил стремится поддерживать обратную совместимость, чего бы это ни стоило.
Кстати, я даже не особо против этого! Обратная совместимость — это очень важно для многих людей, и на то у них есть веские причины. Но других она особо не волнует. Не важно, какая из групп «права»: просто их взгляды несовместимы.
Последствия
Именно поэтому ситуация с профилями именно такова: профили безопасности не предназначены для решения проблем современных, технологически продвинутых корпораций, пишущих на C++. Они нужны для улучшений без необходимости внесения изменений в старый код.
Аналогичная ситуация и с модулями. Пользователь должен иметь возможность «просто» импортировать файл заголовка как модуль, и при этом не должно возникать никаких проблем с обратной совместимостью.
Разумеется, всем нравятся фичи, которые можно просто добавить и которые вносят улучшения без необходимости менять старый код. Но достаточно очевидно, что эти фичи проектировались с учётом в первую очередь «легаси-C++». Поэтому любая фича, которая потребует миграции с легаси-C++ — не вариант для комитета по C++, ведь, как сказал Херб Саттер, по сути, нельзя ожидать, что люди будут выполнять миграцию.
(Повторюсь, создание фич с учётом легаси-C++ — это не плохо. Это вполне разумное решение.)
Именно об этом я стараюсь не забывать, читая статьи по C++: существует две крупные аудитории. Одна предпочитает современный C++, вторая — легаси-C++. У этих двух лагерей есть огромные разногласия, а многие статьи написаны с учётом потребностей конкретной группы.
Очевидно, это приводит к тому, что каждый говорит о своём: что бы ни думали люди, на самом деле профили безопасности и Safe C++ стремятся решать совершенно разные проблемы для разных аудиторий, а не одинаковые.
Комитет по C++ предпринимает усилия к тому, чтобы эта пропасть не расширялась. Предположительно, именно поэтому любые движения в сторону Safe C++ Шона Бакстера для них неприемлемы. Это радикальное изменение, способное создать фундаментально новый способ написания кода на C++.
Разумеется, есть ещё и вопрос, не являются ли отдельные члены комитета по стандарту C++ просто крайне упёртыми людьми, хватающимися за соломинку, чтобы помешать эволюции, с которой они не согласны эстетически.
Я далёк от того, чтобы кого-то обвинять, но не в первый раз слышу, что комитет по C++ использует двойные стандарты вида: «Чтобы утвердить это предложение, мы ожидаем увидеть полную работающую реализацию для множества работающих компиляторов, но с радостью занимаемся отдельными крупными проектами (например, модули и профили), не имеющими функционального доказательства реализации концепции».
Если это так (не могу сказать с уверенностью), то нельзя сказать, как долго ещё C++ будет двигаться по этому пути без гораздо более серьёзного разрыва между двумя лагерями.
И мы ведь даже ещё не касались огромной кучи проблем, которую бы вызвала поломанная совместимость ABI.
Автор: PatientZero