Недавно я опубликовал мнение о фундаментальной экономической модели разработки ПО, которая не способствует (и объективно не должна способствовать) массовому переходу с 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)


  1. unC0Rr
    10.04.2026 08:41

    Языки, ставящие совместимость с C++ во главу, уже есть, например Carbon. Вот только популярности они не набирают.


    1. rsashka Автор
      10.04.2026 08:41

      Ну так это обязательно, но не достаточно условие


      1. v_0ver
        10.04.2026 08:41

        Есть Rust, который можно сказать одной ногой в мейнстриме. Поэтому это не обязательное условие.


        1. rsashka Автор
          10.04.2026 08:41

          Обратная совместимость с миллиардами строк кода, написанными за последние 30-40 лет, это не обязательное условие? Ну-ну…


          1. v_0ver
            10.04.2026 08:41

            Ну я же привёл в качестве примера Rust, на котором ваше утверждение ломается.

            Как уже выше заметили всякие cpp2, carbon, circle, safecpp, D и другие попытки не увенчались успехом. Из этого всего я бы сделал обратный вывод вашему - если вы ставите во главу угла обратную совместимость с С++ то ваш язык провалится.


            1. eao197
              10.04.2026 08:41

              Как уже выше заметили всякие cfront

              cfront – это первый компилятор С++.

              carbon

              пока еще не родился вовсе.

              D

              У D никогда не было совместимости с C++. Впрочем, у D толком и с самим собой совместимости-то и не было нормальной.

              Я это к тому, что языков, которые бы обеспечивали совместимость с C++ и обладали бы теми же особенностями (нативный язык, без GC), вообще как бы и нет.


              1. v_0ver
                10.04.2026 08:41

                Я это к тому, что языков, которые бы обеспечивали совместимость с C++ и обладали бы теми же особенностями (нативный язык, без GC), вообще как бы и нет.

                В том то и дело, что возможно, и это пока подтверждается на практике, язык совместимый с С++, но без его изъянов невозможен.


                1. rsashka Автор
                  10.04.2026 08:41

                  Изъяны С++ вытекают из его семантики и стандартов, тогда как для обеспечения низкоуровневой обратной совместимости достаточно реализовать компилятор языка как трансплайтер в С++.


                1. eao197
                  10.04.2026 08:41

                  Отсутствие таких языков можно объяснить не только “невозможностью”, но и “ненужностью”. Грубо говоря, уже есть C++, можно брать и пользоваться. А раз так, то зачем что-то еще?

                  Востребованными как раз оказываются языки, которые дают в замен что-то другое. Например:

                  • Java – переносимость на уровне скомпилированного кода, безопасность, GC;

                  • Go – безопасность, GC;

                  • Rust – безопасность.

                  При этом пользователям данных языков вообще не вперлась совместимость с С++. Там достаточно какой-то совместимости с Си для FFI. А там, где совместимость с C++ все еще вперлась и нельзя просто так взять и переписать, то C++ и остается. И если он там остается, то зачем какие-то условные замены, если C++ и так справляется.


              1. Siemargl
                10.04.2026 08:41

                D имеет пары по abi: ldc + clang или gcc + gdc, и пытается как то обеспечить частичную совместимость, что непросто

                Nim, V - вообще транспилеры в С, как хочет автор

                Но проблема в том, что в С++ слишком много возможностей, и обеспечить с ними совместимость это будет ещё один С++

                Итого - утопия


                1. rsashka Автор
                  10.04.2026 08:41

                  Автор считает, что нужен трансплитеор не в С, а именно в С++ как раз для того, чтобы была возможность реализовать обратную совместимость с С++ в каком угодно объеме.


                  1. Siemargl
                    10.04.2026 08:41

                    В Nim есть транспиляция в C++ compileToCpp, не смотрел как работает.

                    В С транспиляция нима выглядит ужасной.

                    Не представляю реального практического смысла. Слишком много граблей


              1. Chaos_Optima
                10.04.2026 08:41

                Ну не правда, есть cppfront ну или как его ещё называют cpp2 от Саттера. Компилируется в С++ и его можно смешивать с существующим С++.


                1. eao197
                  10.04.2026 08:41

                  Ну не правда, есть cppfront

                  Он есть как экспериментальный пет-проджек от Саттера. Делать на cppfront проект для продакшена вряд ли стал бы сам Саттер.


            1. rsashka Автор
              10.04.2026 08:41

              Пример Rust - это демонстрация невозможности его применения как прямой замены С++ и использование только в нишевых областях или отдельных проектах без легаси кода.

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


              1. boldape
                10.04.2026 08:41

                Т.е. достаточно поменять экономическую логику (привет АНБ) что бы совместимость с существующим с++ кодом перестала быть самой важной и вся ваша логика рушится следом.

                Также я не оч представляю вас топящим за использование раста в гипотетический ситуации что кто-то выкатит транспайлер из раста в плюсы. Раст вам просто не нравится и ничего в мире это не поменяет.


    1. eao197
      10.04.2026 08:41

      Языки, ставящие совместимость с C++ во главу, уже есть, например Carbon.

      А он уже есть? Вроде как был в состоянии эксперимента, так и остается.


  1. rsashka Автор
    10.04.2026 08:41

    Сделал опрос для статьи, чтобы была конкретика для обсуждения


  1. Goron_Dekar
    10.04.2026 08:41

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

    А вот во всех остальных языках, кроме плюсов, мне не хватает такого огромного зеро-кост абстракционизьма и совместимости с ядерным/железным API (также зеро-кост)


    1. SilverTrouse
      10.04.2026 08:41

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


      1. X-Ray_3D
        10.04.2026 08:41

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


      1. rsashka Автор
        10.04.2026 08:41

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


        1. Dooez
          10.04.2026 08:41

          Стандарт ещё совсем недавно финализировали и уже 2 частичных имплементации есть.

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

          Как ни странно, но я больше переживаю за clang, так как там вся работа велась в форке. Хоть этот форк и появился очень давно, в апстриме только первые этапы имплементации (хотя может за пару недель с последнего просмотра дела поменялись)

          Если просуммировать: ваш комментарий излишне пессимистичный)


          1. rsashka Автор
            10.04.2026 08:41

            Функционал уже очень близкий к полному.

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

            Про отдельный форк clang с реализацией рефлексии я знаю, но так не сумел его протестить самостоятельно. Решил дождаться официального анонса хоть в каком нибудь виде.