Недавно я опубликовал мнение о фундаментальной экономической модели разработки ПО, которая не способствует (и объективно не должна способствовать) массовому переходу с C/C++ на «безопасные» языки программирования Экономика безопасности кода или почему Rust не нужен.
Но чтобы оставаться честным перед читателями, решил опубликовать и статью-контраргумент с описанием обратной стороны медали, то есть почему C++ всё равно будет рано или поздно заменён, а заодно попробовать разобрать, каким будет новый язык программирования, который неминуемо придёт на смену C++.
Проблемы C++ и тупик эволюции
Невозможность безопасного управления памятью и неопределённое поведение (UB) стали частью стандарта С++. Они встроены в его основу. Макросы, заголовочные файлы, частичная специализация, SFINAE, правила инициализации - любая попытка изменения С++ часто упирается в то, что уже существует множество легального кода, который зависит от текущих правил. И нужно либо сохранять старое поведение, потому что отказ от UB или переход на строгую проверяемую модель управления памятью сразу ломает множество допущений в существующем коде или делать новую концепцию параллельно со старой, что еще больше увеличивает сложность языка.
Поэтому за успехом C++ скрывается парадокс: чем более устоявшимся становится стандарт языка, тем сложнее вносить в него изменения. Организационно это означает необходимость синхронизации большого числа участников процесса: разработчиков компиляторов, библиотек, представителей компаний и независимых экспертов, каждый из которых представляет различные интересы. Кто-то борется за безопасность памяти, кто-то - за нулевые накладные расходы, и всё это происходит с учётом обязательств перед работодателем и личных амбиций.
В результате C++ сам себя загнал в ловушку. Его проблемы известны десятилетиями, предложения обсуждаются годами, а быстро принять дополнения в стандарт можно только то, что почти ни с чем не конфликтует и, соотвественно, ни на что не влияет :-(. И для языка, который претендует на роль основного инструмента системного программирования, это уже не недостаток. Это ахиллесова пята.
Парадокс современных «C++ killers»
Поэтому неудивительно, что регулярно возникают языки-«убийцы C++». Почти каждый новый системный язык в какой-то момент позиционировался как кандидат на замену С++: безопаснее память, лучше параллелизм, понятнее ошибки, современнее модель разработки. Многие из этих языков действительно успешны в своих нишах и нередко превосходят C++ по эргономике и безопасности. Но как замена C++, в смысле массового вытеснения его из существующих больших кодовых баз, у них не получается. И причина здесь часто не в синтаксисе и даже не в качестве компилятора.
Главный барьер - это совместимость. C++ - это не только язык. Это библиотеки, ABI, соглашения о вызовах, бинарные интерфейсы, инструменты сборки, линковщики, дебаггеры, профилировщики, санитайзеры, сертификации, тысячелетние make/CMake/Bazel-скрипты, тонны заголовков и макросов, миллионы строк «встроенной культуры» кодирования. Когда новый язык приходит со своим компилятором (пусть даже он и использует LLVM как backend), он приносит с собой новый набор границ: как смешивать модули, как линковаться с существующими библиотеками, как дебажить стек вызовов, как гарантировать совместимость исключений, RTTI, манглинг имён и соглашений о вызовах на разных платформах.
В теории легко сказать «у нас есть FFI». На практике же FFI - это extern "C", что недостаточно для взаимодействия с C++ с его шаблонами, инлайнами, перегрузками, SFINAE, ADL и культурой header-only библиотек. Большая часть современной C++ -экосистемы не является удобным C API, а представляет собой набор заголовков, которые предполагают, что потребитель тоже компилируется как C++ и живёт по тем же правилам.
Почему-то все языки, убийцы C++, забыли очень полезный исторический урок. Ранний компилятор C++ (тогда ещё «C с классами») - cfront - был выполнен как транспайлер, который превращал программу C++ в обычный исходный код на C. Это означало, что любой существующий C-компилятор мгновенно становился способом «компилировать C++». Любой существующий линковщик, отладчик и профилировщик оставались на месте. Риск использования нового языка уменьшался многократно, ведь можно было начинать использовать новые возможности, не переучивая разработчиков и не перестраивая весь производственный процесс.
Однако все современные «замены C++» часто выбирают противоположный путь: создают собственный компилятор и собственную платформу исполнения (пусть даже и опирающуюся на LLVM). Технически это понятный выбор: проще обеспечить целостную систему и лучше диагностика. Но цена такого выбора - создание барьера совместимости. Там, где Cfront снимал проблему интеграции со старым исходным кодом, новый компилятор порождает её заново: нужно решать вопрос бинарных границ, отладки, смешивания с legacy-библиотеками, сборки, деплоя и политики обновлений. В результате новый язык может быть эстетически прекрасным, но он становится возможной альтернативой только для новых проектов, но никак не «заменой C++» в смысле миграции гигантских кодовых баз.
Новый язык на замену C++
Поэтому наиболее реалистичный сценарий появления настоящей замены C++ выглядит иначе. Она вырастет из транспайлера, который генерирует C или, вероятнее, C++ как целевой язык. Транспайлер даёт главное, что нужно на масштабе C++: инкрементальность. Можно начать с одного компонента, одного файла, одной подсистемы, не переписывая всё. Сборка остаётся прежней, линковка остаётся прежней, ABI остаётся прежним, инструменты остаются прежними.
«Новый язык» становится фронтендом, который постепенно отвоёвывает территорию внутри существующего мира, а не требует построить новый мир рядом. При этом можно вводить безопасность «по умолчанию», оставляя явно помеченные «unsafe»-участки там, где нужно взаимодействовать с низкоуровневой реальностью. И самое важное: можно быть совместимым не только с C как минимальным знаменателем, но и с C++ - экосистемой в целом.
Конечно, транспайлинг, это не панацея и такой подход создаёт свои сложности: качество генерируемого кода, читаемость, соответствие отладочной информации, точность отображения исходных абстракций и необходимость использования C++ компиляторов. Но эти сложности могут быть более приемлемыми, чем полномасштабная смена компилятора и всей инфраструктуры. Поэтому транспайлер - это способ свести риски перехода на новый язык к контролируемой величине и сделать миграцию на новый язык экономически возможной.
Отсюда можно сделать вывод, что скорее всего победит не обязательно самый «чистый» или «правильный» язык, а тот, у которого будет самый низкий барьер использования в уже существующей экосистеме. C++ когда-то победил именно так - не качеством языка, а простотой интеграции с уже существующими решениями. Поэтому, если когда-то и появится замена C++, которая действительно станет массовой, то она, скорее всего, начнётся с транспайлера: как надстройка над C++, которая в первую очередь совместима, и только потом удобнее и безопаснее.
Комментарии (45)

Goron_Dekar
10.04.2026 08:41Мне в плюсах не хватает только ява-лайк рефлексии, но я прекрасно понимаю, почему его нет и без стрёмных костылей не может быть.
А вот во всех остальных языках, кроме плюсов, мне не хватает такого огромного зеро-кост абстракционизьма и совместимости с ядерным/железным API (также зеро-кост)

SilverTrouse
10.04.2026 08:41Ну базовая рефлексия уже есть в С++26. Остался только token injection для полного счастья

X-Ray_3D
10.04.2026 08:41Руки чесались добавить в КЛанг или ГКК, но не потяну… Хотя малыми издержками есть мысли, как это добавить (вариант от ЭДГ). Или ЭДГ спереть с КЭ)))

rsashka Автор
10.04.2026 08:41К сожалению, только базовая и только в виде требований, пока без поддержки в компиляторах

Dooez
10.04.2026 08:41Стандарт ещё совсем недавно финализировали и уже 2 частичных имплементации есть.
Функционал уже очень близкий к полному. Из-за комбинаторной сложности темплейтов + рефлексии некоторых вещей можно добиться разными путями, и не все пути работают.
Как ни странно, но я больше переживаю за clang, так как там вся работа велась в форке. Хоть этот форк и появился очень давно, в апстриме только первые этапы имплементации (хотя может за пару недель с последнего просмотра дела поменялись)
Если просуммировать: ваш комментарий излишне пессимистичный)

rsashka Автор
10.04.2026 08:41Функционал уже очень близкий к полному.
Вы зря меня считаете пессимситом, я скорее реалист, так как это изначальное предложение по рефлексии было близким к полной, но потом её ужали только до рефлексии типов, чтобы хоть с чего-то начать. Это тоже очень хорошо, так как с помощью C++26 можно закрыть некоторые проблемы.
Про отдельный форк clang с реализацией рефлексии я знаю, но так не сумел его протестить самостоятельно. Решил дождаться официального анонса хоть в каком нибудь виде.
unC0Rr
Языки, ставящие совместимость с C++ во главу, уже есть, например Carbon. Вот только популярности они не набирают.
rsashka Автор
Ну так это обязательно, но не достаточно условие
v_0ver
Есть Rust, который можно сказать одной ногой в мейнстриме. Поэтому это не обязательное условие.
rsashka Автор
Обратная совместимость с миллиардами строк кода, написанными за последние 30-40 лет, это не обязательное условие? Ну-ну…
v_0ver
Ну я же привёл в качестве примера Rust, на котором ваше утверждение ломается.
Как уже выше заметили всякие cpp2, carbon, circle, safecpp, D и другие попытки не увенчались успехом. Из этого всего я бы сделал обратный вывод вашему - если вы ставите во главу угла обратную совместимость с С++ то ваш язык провалится.
eao197
cfront – это первый компилятор С++.
пока еще не родился вовсе.
У D никогда не было совместимости с C++. Впрочем, у D толком и с самим собой совместимости-то и не было нормальной.
Я это к тому, что языков, которые бы обеспечивали совместимость с C++ и обладали бы теми же особенностями (нативный язык, без GC), вообще как бы и нет.
v_0ver
В том то и дело, что возможно, и это пока подтверждается на практике, язык совместимый с С++, но без его изъянов невозможен.
rsashka Автор
Изъяны С++ вытекают из его семантики и стандартов, тогда как для обеспечения низкоуровневой обратной совместимости достаточно реализовать компилятор языка как трансплайтер в С++.
eao197
Отсутствие таких языков можно объяснить не только “невозможностью”, но и “ненужностью”. Грубо говоря, уже есть C++, можно брать и пользоваться. А раз так, то зачем что-то еще?
Востребованными как раз оказываются языки, которые дают в замен что-то другое. Например:
Java – переносимость на уровне скомпилированного кода, безопасность, GC;
Go – безопасность, GC;
Rust – безопасность.
При этом пользователям данных языков вообще не вперлась совместимость с С++. Там достаточно какой-то совместимости с Си для FFI. А там, где совместимость с C++ все еще вперлась и нельзя просто так взять и переписать, то C++ и остается. И если он там остается, то зачем какие-то условные замены, если C++ и так справляется.
Siemargl
D имеет пары по abi: ldc + clang или gcc + gdc, и пытается как то обеспечить частичную совместимость, что непросто
Nim, V - вообще транспилеры в С, как хочет автор
Но проблема в том, что в С++ слишком много возможностей, и обеспечить с ними совместимость это будет ещё один С++
Итого - утопия
rsashka Автор
Автор считает, что нужен трансплитеор не в С, а именно в С++ как раз для того, чтобы была возможность реализовать обратную совместимость с С++ в каком угодно объеме.
Siemargl
В Nim есть транспиляция в C++ compileToCpp, не смотрел как работает.
В С транспиляция нима выглядит ужасной.
Не представляю реального практического смысла. Слишком много граблей
Chaos_Optima
Ну не правда, есть cppfront ну или как его ещё называют cpp2 от Саттера. Компилируется в С++ и его можно смешивать с существующим С++.
eao197
Он есть как экспериментальный пет-проджек от Саттера. Делать на cppfront проект для продакшена вряд ли стал бы сам Саттер.
rsashka Автор
Пример Rust - это демонстрация невозможности его применения как прямой замены С++ и использование только в нишевых областях или отдельных проектах без легаси кода.
Тогда как для замены С++ - обеспечение обратной совместимости - это обязательное, хоть и не достаточное условие согласно банальным экономическим соображениям.
boldape
Т.е. достаточно поменять экономическую логику (привет АНБ) что бы совместимость с существующим с++ кодом перестала быть самой важной и вся ваша логика рушится следом.
Также я не оч представляю вас топящим за использование раста в гипотетический ситуации что кто-то выкатит транспайлер из раста в плюсы. Раст вам просто не нравится и ничего в мире это не поменяет.
eao197
А он уже есть? Вроде как был в состоянии эксперимента, так и остается.