[Перевод] Размышление о двух подходах к C++

Похоже, мечтам о создании единого бездиалектного C++ не суждено будет сбыться.

Zero Ranger.

Zero Ranger.

Будущее C++ уже не первый год служит поводом для огромного количества разногласий.

Возможно, вы подумаете, что я говорю о профильных тредах на Reddit — местная публика давно славится своей многополярностью и любовью к спорам ради спора, так что разговоры на повышенных тонах там в принципе никогда не утихают. Однако гораздо страннее их видеть даже на официальных заседаниях комитета по стандартизации C++. Ниже я приведу несколько красноречивых примеров.

Текущее положение дел C++

Вот в какой интересной ситуации мы оказались в последнее время:

  • C++«s Evolution Working Group (EWG) недавно выпустила документ P3466 R0 — (Re)affirm design principles for future C++ evolution. Особенно интересно в разрезе статьи следующее:

    • Принято решение не менять ABI в целях сохранения совместимости с C и прошлыми версиями C++.

    • Не появится т.н. «паразитных аннотаций» (например, аннотаций времени жизни).

    • Целый набор взаимоисключающих целей: например, и ABI не поменяется, и zero-overhead principle по-прежнему в строю.

В то же самое время происходят другие, не менее интригующие события:

  • Правительство США выступает против использования языка C++:

    • CISA

    • NSA

    • Даже Белый дом

    • Кроме шуток, различные ветви государственной власти США выпускают документ за документом, пропагандируя отказ от повсеместного использования языков с небезопасным доступом к памяти.

  • Представители Big Tech вовсю лоббируют переход к Rust:

  • К слову о Big Tech, вы заметили, что Герб Саттер покинул Microsoft, а MSVC как-то чересчур неторопливо внедряет функции C++ 23 и просит у сообщества помощи в определении приоритетов.

  • После печально известного пражского ABI-голосования («В C23 ABI не претерпит изменений, и неясно, случатся ли они вообще») Google значительно сократила свое участие в процессе развития C и вместо этого начала работать над собственным языком-преемником C++. У них даже имеется документ с описанием проблем, с которыми они столкнулись при попытке «улучшить» C++.

  • В сообществе набирают популярность истории людей, которые в течение многих лет изо всех сил стремились принять участие в работе комитета по стандартизации C++, но их попросту пережевывали и выплевывали. 

  • Модули до сих пор не имплементированы [Are we modules yet?](https://arewemodulesyet.org/)

    image

    image

  • «Профили безопасности» до сих пор находятся в состоянии «ни жива, ни мертва» и не получили какой-либо реализации. Шон Бакстер занял позицию против профилей и назвал C++ «недоспецифицированным».

Не знаю, какие выводы из этой информации сделали вы, но, на мой взгляд, все это напоминает развал C++. Кажется, будто комитет по C++ из последних сил справляется со своими обязанностями. Впрочем, я не хочу, чтобы вы поняли меня превратно. C++ сам по себе никуда не денется — речь идет именно о том, какое развитие он получит в ближайшие годы.

Две разные культуры C++

Всем приходится самостоятельно искать новые решения.

Возьмем для примера уже упомянутую выше компанию Google. Очевидно, Google потеряла веру в развитие C++ после голосования по ABI. Это не потеря веры в сам язык, у Google одна из самых больших кодовых баз на C++ в мире. Этот язык сослужил компании невероятную службу. Скорее, это потеря веры в способность языка развиваться в условиях давления сразу с нескольких сторон (актуальные и потенциальные постановления правительства, наличие языков-конкурентов, желание добиться более высокой производительности, гарантии безопасности от ключевых игроков и т. д.).

Но в чем же корневая проблема? Почему нельзя просто собраться всем миром, взять и…изменить C++ в нужную сторону?

Никакого секрета здесь нет. Просто взгляните, что Герб Саттер писал в своей статье о профилях:

Мы должны свести к минимуму необходимость изменения существующего кода. Что касается внесения изменений в существующий код, то многолетний опыт показывает, что большинство владельцев крупных кодовых баз не захотят и не станут менять даже 1% от общего объема кода для удовлетворения новых правил строгости, даже из соображений безопасности. Разве что их принудят к этому нормативные требования». — Герб Саттер

Круто. Кого-то это удивляет? Меня — ни капельки.

А теперь для контраста ознакомимся с фрагментом биографии Чендлера Каррута, представленной на его страничке на WG21:

Я руководил разработкой инструментария для C++ и систем автоматического рефакторинга, построенных на основе Clang и теперь являющихся частью проекта Clang. 

[…]

В Google я возглавил направление, занимавшееся масштабированием автоматизированных инструментов рефакторинга на основе Clang на всю нашу кодовую базу, а это более 100 миллионов строк C++ кода. Теперь мы можем провести анализ, а затем и рефакторинг всей кодовой базы всего за 20 минут.

Ого. Видите это? (Конечно, видите, ведь я специально выделил жирным нужные части текста).

Речь идет про некий «автоматизированный инструментарий». Но за этими словами стоит гораздо больше. Автоматизированный инструментарий — это лишь вершина айсберга, единичный яркий пример.

По сути, сейчас мы наблюдаем конфликт между двумя кардинально отличающимися лагерями пользователей C++:

  • Относительно современные, компетентные технологические корпорации, которые понимают, что их код — это актив. (Это не обязательно представители big tech. Любой вменяемый стартап, пишущий свежий код на C++, также попадает в эту категорию).

  • Все остальные. Замшелые конторы, где люди до сих пор спорят о том, как правильно делать отступы, а молодой инженер умоляет руководство разрешить ему установить линтер.

Первая группа сможет адаптироваться к переходу на новые стандарты с наименьшими проблемами, поскольку она будет в состоянии собрать собственный стек C++ из исходников, полученных из репозиториев GitHub-проектов и пакетных менеджеров. (Примечание переводчика: Автор оригинальной статьи использует термин »версионированный источник») А вторая, по-прежнему использующая устаревшие предсобранные библиотеки из 1998 года, будет обречена на страдания.

Умение собрать весь стек зависимостей из исходников нужных версий (желательно еще и с автоматизированными тестами) — это, пожалуй, самое важное отличие между двумя лагерями.

На практике, конечно, чаще встречается нечто среднее. Представляю, сколько пота, слез, денег и крови утекло, чтобы превратить огромные кодовые базы из ужасающих клубков грязи в полууправляемые, собираемые, линкуемые и чуть менее ужасающие клубки грязи.

Теперь, оглядываясь назад, легко рассуждать о неизбежности этих процессов: существовало явное несоответствие между потребностями корпораций вроде Google (которые используют относительно современный C++, имеют автоматизированный инструментарий и тестирование, а также современную инфраструктуру), и огромным интересом всего остального мира к обратной совместимости.

Если говорить на чистоту, то идея единого, свободного от диалектов и унифицированного C++, похоже, умерла уже много лет назад. C++ сейчас существует в мире в двух агрегатных состояниях:

  • Любой относительно современный C++. Все собирается из исходников подходящей версии посредством специального унифицированного сборщика, который, по крайней мере, немного сложнее, чем голый CMake, и выглядит как вполне адекватно работающий, если слегка прищуриться. Всякие статические анализаторы, форматировщики, линтеры. Любое соглашение о необходимости поддерживать кодовую базу чистой и современной в этом случае бесценно. Возможно, даже C++17, с unique_ptr, constexpr, optional и лямбдами. Но это не самое главное. Важнее всего инструментарий.

  • Устаревший C++. Все, что отличается от написанного выше. Любой C++, который засел в древних, запыленных серверах какого-нибудь банка. Любой C++, который опирается на кусок непонятно кем и когда скомпилированного кода. Исходники давно утеряны, а авторы наверняка на том свете. Любой C++, развернутый на любительском сервере настолько криво, что его перенос на новое место займет у инженера целый месяц, поскольку ему придется разобраться со всеми неявными зависимостями, конфигурациями и переменными окружения. Любая кодовая база, которая больше напоминает не актив, а черную дыру, засасывающую деньги. Любой код, в котором сборка бинарника из исходного кода требует больше пары нажатий кнопок или вообще невозможна.

Обратите внимание, основное различие заключается не в самом C++. В первую очередь это инструментарий и возможность сборки из исходного доступного через систему контроля версий кода любым чистым, четко определенным способом. В идеале, даже возможность развертывания без необходимости помнить о флагах или переменных окружения, которые обычно устанавливал предыдущий разработчик, чтобы все не рухнуло.

То, насколько кодовая база Google соответствует «современным» стандартам C++, в значительной степени вторично по отношению к тому, насколько хорош ее инструментарий и можно ли собрать проект из исходников без танцев с бубном.

Многие здесь возразят, мол, комитет по стандартизации C++ никак не отвечает за инструментарий, и они будут правы. Это сделано намеренно: комитет в ответе за спецификацию языка C++, а не конкретные реализации.

К слову о Go. Если в Go и есть что-то хорошее, так это инструментарий. C++ по сравнению с ним — это натуральный мамонт. У C++ нет единой системы сборки, ничего даже близко похожего на единую систему управления пакетами, а еще его невероятно сложно разбирать и анализировать (это очень важно с точки зрения инструментария).

Между описанными выше лагерями (хороший инструментарий, можно без усилий собрать всё из исходников, против плохого инструментария, нельзя ничего собрать из исходников) существует огромный, постоянно увеличивающийся разрыв, и я, честно говоря, не думаю, что в ближайшее время он будет ликвидирован.

Комитет по C++, кажется, очень привержен поддержанию обратной совместимости, поэтому и не считается с ценой, которую приходится за нее платить.

Я не могу здесь однозначно принять чью-то сторону. Многим обратная совместимость совершенно необходима, причем по крайне веским причинам. Другим она попросту не нужна. Нельзя говорить, что кто-то из них не прав: это всего лишь разные, взаимоисключающие взгляды на проблему.

Последствия

Именно поэтому вопрос с профилями уже почти два года никуда не движется: их имплементация нужна не для разрешения проблем современных, продвинутых в технологическом плане корпораций, использующих C++. Перед ними стоит совершенно другая задача: привнести в язык улучшения, не требующие переписывать старый код.

То же самое касается и модулей. Предполагается, что можно будет «всего-навсего» импортировать заголовочный файл как модуль, и при этом не возникнет никаких проблем с обратной совместимостью.

Конечно, всем нравятся функции, улучшающие язык, внедрение которых не повлечет за собой необходимость переписывать старый код. Поэтому, очевидно, и разрабатываются они с прицелом на «устаревший» C++. И любая функция, которая потребует перехода с «устаревшего» C++, для комитета C++ не имеет смысла, поскольку, как сказал Герб Саттер, нельзя ожидать, что все просто возьмут и перейдут на новую версию языка.

(Повторюсь, создавать функции с учетом «устаревшего» C++ вовсе не плохо. Это вполне разумное решение.)

Вот, о чем я стараюсь помнить, когда читаю статьи о C++: у него есть две большие целевые аудитории. Одна — современная, другая — традиционная. Эти два лагеря сильно расходятся во мнениях, и многие статьи пишутся с учетом потребностей какой-то одной конкретной группы.

Это порождает в сообществе споры и кривотолки: что бы там кому ни казалось, профили безопасности и Safe C++ пытаются решить совершенно разные проблемы двух разных аудиторий.

Комитет по C++ стремится не допустить увеличения этого раскола. Вероятно, поэтому все, что делает Шон Бакстер в ключе Safe C++, для них не имеет смысла. Это радикальное, масштабное изменение, которое может создать принципиально новый способ работы с C++.

Конечно, здесь может возникнуть другой вопрос:, а не являются ли конкретные члены комитета по стандартизации C++ обыкновенными упрямцами, которые хватаются за последнюю соломинку, лишь бы не допустить в языке эволюции, с которой они лично эстетически не согласны.

Не мне судить кого-либо, но я не впервые слышу, что комитет по C++ придерживается двойных стандартов. Вот, например: «Мы ожидаем от вас полной, рабочей реализации в нескольких компиляторах, если вы хотите, чтобы это предложение было одобрено, но при этом с радостью возьмем на себя обязательства по ряду обширных проектов (например, по модулям или профилям), которые до сих поре не имеют работающей реализации».

Если так и есть, то я не знаю, как долго аудитория C++ еще просуществует в относительно целостном виде.

И всё это — при условии, что ABI в ближайшее время не будет подвергаться изменениям.

© Habrahabr.ru