Язык программирования C++, на котором написано 95% существующего программного обеспечения, был создан Бьерном Страуструпом, датским инженером со странноватой прической, в далеком 1985 году — очень давно!

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

Но 40 лет — это много. Все это время IT-индустрия открывала инсайты, меняла подходы к разработке ПО, придумывала новые методологии и архитектуры, развивала другие языки и их синтаксисы. В общем, аспекты разработки сильно менялись, эволюционировали.

Поспевал ли за этими изменениями C++? Он старался. И старается до сих пор. НО!

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

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

Это что касается контекста. Если говорить о технических недостатках (они же, кстати, могут считаться и достоинствами, ибо тут с какой стороны посмотреть), то озвучиваются они обычно так: «Да, С++ очень быстрый, экономит память и батарею, но он совсем не безопасный — позволяет выходить за границы массивов, обращаться к освобожденным кускам памяти и все такое».

Короче говоря, низкоуровневая свобода имеет свои издержки. И делает язык сложнее и опаснее.

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

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

1. Rust

Rust — язык программирования общего назначения, увидевший мир в 2015 году. Так же, как и C++, он делает упор на производительность, типизацию и параллелизм.

Однако в отличие от «плюсов», он обеспечивает полную безопасность памяти — все ссылки указывают только на допустимую память. При этом Rust не использует автоматический сборщик мусора — вместо этого он отслеживает время жизни объекта и его ссылки еще на стадии компиляции программы.

Rust, как и C++, используется в системном программировании. Язык довольно нейтрален и не навязывает какую-либо парадигму программирования, но во многом он построен на идеях функционального программирования. Разумеется, в языке есть все необходимые типы данных и для ООП: структуры (struct), перечисления (enum), черты (trait) и методы (fn).

Вот небольшой пример кода на Rust:

// entry point в программу
fn main() {
  let width1 = 30;
  let height1 = 50;

  println!("Площадь прямоугольника: {} пикселей", area(width1, height1)); // здесь выполняется конвертация тип u32 при передаче аргументов в функцию
}

// пользовательская функция, считающая площадь прямоугольника
// принимает в качестве параметров и возвращает целочисленный тип u32
fn area(width: u32, height: u32) -> u32 {
  width * height
}

Изначально Rust появился как личный проект Грейдона Хоара в 2006 году, когда он работал в Mozilla Research.

«Rust» переводится как «ржавчина». Однако речь идет не о процессе окисления металла, а о грибковых патогенах, которые покрывают листья растений в характерный коричневый цвет, напоминающий ржавчину.

В 2009 году Mozilla начала спонсировать Rust официально и наняла десяток инженеров для помощи Грейдону.

В 2011 году, как часто бывает у языков программирования, компилятор Rust смог скомпилировать сам себя. Тогда же появился привычный логотип с шестеренкой — на самом деле это велосипедная передача для цепи.

До 2015 года Rust был внутренним проектом — о нем мало кто знал и он нигде не использовался. Но именно после 2015 года Rust стал выглядеть, как потенциальный преемник C++. тогда вышел первый стабильный релиз Rust 1.0.

После коронавируса (в рамках реструктуризации) Mozilla стала увольнять сотрудников, многие из которых работали над Rust. В итоге из-за различных опасений в 2020 году был создан фонд — Rust Foundation. В него вошли пять компаний-основателей, заинтересованных в поддержке языка: Mozilla, AWS, Huawei, Google, Microsoft.

Более того, с 2021 года Google теперь поддерживает Rust в разработке приложений для Android наравне с C/C++.

Основные отличия Rust от C++:

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

  • Безопасная память. Rust использует так называемую систему «владения и заимствования» для управления памятью, тем самым предотвращая утечки и ошибки на уровне компиляции. Компилятор проверяет время жизни переменных и гарантирует отсутствие обращений к уже освобожденной памяти. C++, напротив, позволяет вручную управлять памятью с помощью соответствующих ключевых слов и функций: new, delete, malloc и free. Да, это увеличивает гибкость, но в то же время требует от программиста большей осторожности.

  • Единообразная компиляция. У Rust есть основной компилятор, который поставляется с пакетным менеджером Cargo для управления зависимостями и сборки проектов. В этом смысле Rust более един и централизован. А значит, в его инфраструктуре сложнее запутаться. А вот у C++ есть множество поставщиков компиляторов (GCC, Clang, MSVC), каждый из которых по-своему поддерживает общий стандарт языка. То же касается внешних систем сборки и пакетных менеджеров. Неопытному разработчику это может показаться одним большим беспорядком.

Мем virgin/chad про Rust и C++ (источник: Skillbox Media)
Мем virgin/chad про Rust и C++ (источник: Skillbox Media)

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

Год выпуска

2015

Разработчик

Mozilla (Грейдон Хоар), Rust Foundation

Расширение файлов

.rs и .rlib

Пакетный менеджер

Cargo

Официальный сайт

rust-lang.org

2. Golang

Golang — компилируемый язык программирования, разработанный компанией Google. Хотя обычно его называют просто Go. Но ни в коем случае не путайте Go с Go!последний имеет восклицательный знак в конце названия и является совершенно другим языком программирования.

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

Однако Go не был продуктом энтузиазма какого-либо сотрудника Google — он возник из сугубо прикладной мотивации и был призван решить реальные проблемы, с которыми сталкивался Google при разработке своих сервисов.

Go стремился вобрать в себя простоту динамических языков, вроде Python или Ruby, и производительность компилируемых языков, вроде C и C++. Но, в отличие от «плюсов» и Rust, в Golang имеется сборщик мусора.

Вот пример простого HTTP-сервера на Go:

// объявление главного пакета
package main

// подключение библиотек консольного вывода и работы с HTTP-соединением
import (
    "fmt"
    "net/http"
)

// функция обработки запроса hello
func hello(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "hello\n") // вывод приветствия в консоль
}

// функция обработки запроса headers
func headers(w http.ResponseWriter, req *http.Request) {
    for name, headers := range req.Header {
        for _, h := range headers {
              fmt.Fprintf(w, "%v: %v\n", name, h) // вывод HTTP-заголовка в консоль
    }
  }
}

func main() {
    // поочередное добавление обработчиков запросов к роутеру
    http.HandleFunc("/hello", hello)
    http.HandleFunc("/headers", headers)

    // запуск сервера
    http.ListenAndServe(":8090", nil)
}

Разумеется, Go не настолько быстрый, как C++, но его производительности более чем достаточно для большинства приложений.

А еще у Golang есть собственный встроенный пакетный менеджер Go Package Manager.

Кстати, на Golang написали некоторые популярные инструменты разработки:

  • Docker. Самый известный и, возможно, самый сложный продукт, написанный на Go — открытая платформа для контейнеризации приложений.

  • Kubernetes. Система оркестрации контейнеров, тесно связанная с Docker, тоже написана на Go. Более того, Kubernetes написали сами создатели языка — разработчики из Google. Можно сказать, что Kubernetes — одна из внутренних разработок Google, для которых и задумывался Golang.

  • Container Linux. Не вся целиком, но большая часть компонентов этой легковесной операционной системы написаны на Golang.

Год выпуска

2009

Разработчик

Google

Расширение файлов

.go

Пакетный менеджер

Go Package Manager

Официальный сайт

go.dev

3. Swift

Swift — это язык программирования от компании Apple, который предназначен для разработки приложений на закрытых платформах компании: iOS и macOS. На удивление (учитывая тотальную закрытость всех разработок Apple), язык имеет открытый исходный код.

Также, как и Golang, язык Swift имеет собственный официальный пакетный менеджер The Swift Package Manager — сокращенно просто SwiftPM.

Вот пример кода на Swift, в котором реализована логика отгадывания числа через консоль:

// подключение библиотеки для работы с консолью
import Foundation

// генерация случайного числа от 1 до 100
let secretNumber = Int.random(in: 1...100)
var guess: Int?
var attempts = 0

print("Попробуйте угадать число от 1 до 100.")

// цикл, внутри которого выполняется работа с консолью
while guess != secretNumber {
    print("Введите число: ", terminator: "")

    if let input = readLine(), let number = Int(input) {
        guess = number
        attempts += 1

        if number < secretNumber {
            print("Мое число больше.")
        } else if number > secretNumber {
            print("Мое число меньше.")
        } else {
            print("Поздравляем! Вы угадали число за \(attempts) попыток.")
        }
  } else {
            print("Некорректное число. Введите еще раз.")
  }
}

Из-за закрытости платформ Apple язык Swift подойдет только для:

  • мобильных разработчиков, которые пишут приложения под операционную систему iOS;

  • десктопных разработчиков, которые пишут приложения под операционную систему macOS;

  • геймдев-разработчиков, которые пишут игры игры под все платформы Apple;

  • бэкенд-разработчиков сайтов, которые работают с веб-библиотеками Swift;

То есть любые другие платформы, будь то Windows, Linux или Android, не подойдут для финального запуска приложений, написанных на Swift.

Более того, с большей вероятностью разработчикам, которым нужна качественная поддержка нативных функций Apple, просто придется погрузиться в Swift. Благо его синтаксис похож на другие C-подобные языки.

Год выпуска

2014

Разработчик

Apple

Расширение файлов

.swift

Пакетный менеджер

The Swift Package Manager (SwiftPM)

Официальный сайт

swift.org

4. Carbon

Carbon — это абсолютно новый (он появился в 2022 году) компилируемый язык общего назначения от компании Google, который позиционируется как более синтаксически элегантный преемник C++.

Язык имеет открытый исходный код, поэтому любой желающий может ознакомится с его реализацией в официальном репозитории на GitHub.

На момент 2024 года Carbon все еще находится на стадии экспериментальной версии — готовая к производству ожидается только после 2027 года.

Вот небольшой пример кода на Carbon:

package Geometry; // код ниже будет содержимым пакета Geometry
import Math; // подключение библиотеки с математическими функциями

// пользовательский класс
class Circle {
      var radius: f32; // переменная типа float32
}

// пользовательская функция
fn PrintTotalArea(circles: Slice(Circle)) {
      var area: f32 = 0;

      for (circle: Circle in circles) {
              area += Math.Pi * circle.radius * circle.radius;
      }

      Print("Площадь круга: {0}", area);
}

// entry point, который возвращает переменную типа int32
fn Main() -> i32 {
      // Array является аналогом динамического массива std::vector
      var circles: Array(Circle) = ({.radius = 1.0}, {.radius = 2.0});

      // при передаче аргументов в функцию происходит неявная конвертация типа Array в Slice
PrintTotalArea(circles);

      return 0;
}

Кстати, синтаксис Carbon очень похож на синтаксис Rust, хотя и не полностью. Есть 2 причины появления Carbon. Ну или мотивации его создания:

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

  • Бизнес-решение. Google — это огромная корпорация мирового уровня. Большая часть того, что нас окружает (поисковик, сервисы, Android) — это все Google. И именно он использует C++ больше всего. По этой причине Google на протяжении последних 20 лет вкладывал огромные ресурсы в поддержку и улучшение этого языка, его компиляторов, инструментов (например, Clang-Tidy и Google C++ Style Guide) и библиотек. Во многом он влиял на философию написания кода, которая окутывает язык. А еще долгое время состоял национальной рабочей группе по стандартизации С++. А теперь представьте, что вы хотите внести серьезное (а, возможно, и не серьезное) изменение в язык, но не можете этого сделать — огромный легаси, написанный 20 лет назад и который нечем заменить (либо это очень дорого) просто сломается. Это сильно ограничивает Google в решении технических задач и заставляет сервисы компании стагнировать. Поэтому Carbon — следствие бизнес-потребности Google.

На самом деле Apple сделала то же самое. Компании надоело возиться с крайне инертным C++, и она заменила его его на Swift. Не полностью, но заменила — ядро ОС по-прежнему на «плюсах», а клиентские приложения уже на Swift.

Вот несколько важных особенностей Carbon:

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

  • Централизованная поддержка. Изменения в языке решают только руководством Carbon — никаких комитетов и рабочих групп с многочисленными участниками. С другой стороны, это не исключает получения полезной обратной связи от разработчиков других крупных компаний и IT-гигантов.

  • Регулярные обновления. Новые функции в язык C++ приходится ждать десятилетиями. Пока кто-то придумает новую фичу в виде отдельной библиотеки, пока кто-то ее протестирует, пока о ней узнают в комитете, пока согласуют, доработают, добавят в стандарт и так далее и тому подобное. Короче, целая вечность. С Carbon все иначе — обновления языка, даже самые незначительные, будут выходить регулярно. CI/CD во всей красе!

  • Модульная система. Carbon имеет более интуитивную систему модулей — файлы с кодом объединяются в абстракцию, под названием «пакет». Каждый такой пакет можно импортировать и использовать его функции. В C++ с этим немного сложнее. Нужно выполнять «инклуды» и в явном виде помогать препроцессору языка собрать все воедино. Тем не менее, пакетный менеджер для управления зависимости пока на уровне дискуссии в GitHub — некоторые разработчики, разумеется, желают увидеть официальный пакетный менеджер Carbon.

  • Шаблоны. Система шаблонов в C++ имеет свои нюансы и фишки, многие из которых непонятны новичкам или напрочь контринтуитивны. Шаблонизация в Carbon обещает быть нагляднее — так же, как она реализована в Rust.

Тем не менее Carbon все еще в неопределенности. Никто не знает, что будет с языком завтра. Поэтому, если и учить Carbon сегодня, то только ради интереса и общего развития. На текущий момент действительно стабильная альтернатива C++ — Rust.

Год выпуска

2022

Разработчик

Google (Чендлер Каррут)

Расширение файлов

.carbon

Пакетный менеджер

-

Официальный сайт

github.com/carbon-language/carbon-lang

Заключение

Так или иначе, C++ до сих пор является наилучшим вариантом для инвестирования своего времени, способностей, интеллектуального и психического ресурса. Альтернативы ему нет. Ну, при условии, что вам требуется системное программирование с высоким быстродействием кода.

Тем не менее стоять на месте нельзя. Относительно «древний» каркас C++, берущий свое начало в прошлом столетии, все еще работает и разумеется решает задачи, но не поспевает за современной разработкой.

Даже сам создатель C++ как-то сказал:

Бьерн Страуструп, компьютерный инженер, разработчик первых версий C++
Бьерн Страуструп, компьютерный инженер, разработчик первых версий C++

«Эволюция необходима, чтобы справляться с вызовами меняющегося мира и реализовывать новые идеи».

Evolution is necessary to meet the challenges of a changing world and to incorporate new ideas»)

Старые дома можно реставрировать до поры до времени. Построить же новый мегаполис можно только полностью с нуля — после сноса старого. С соблюдением всех современных стандартов.


НЛО прилетело и оставило здесь промокод для читателей нашего блога:
-15% на заказ любого VDS (кроме тарифа Прогрев) — HABRFIRSTVDS

Комментарии (59)


  1. Gay_Lussak
    27.08.2024 09:41
    +4

    C++, напротив, позволяет вручную управлять памятью с помощью соответствующих ключевых слов и функций: new, delete, malloc и free.

    Уже давно ручное управление памятью является bad practice. RAII-концепция захватывает все больше вещей в С++, начиная с просто умных указателей, заканчивая автоматическим управлением потоками - std::jthread. Проблем конечно хватает даже с умными указателями. Но так манипулировать тоже не стоит.


    1. codecity
      27.08.2024 09:41

      Проблем конечно хватает даже с умными указателями.

      Одна из - перемещение не отслеживается. Но у Rust так же реализовано топорно - если вы переместили внутри некого блока, который даже никогда не исполнится и потом попробуете использовать возможно перемещенное значение - оно уже не даст скомпилировать такой код.


      1. qwerty19106
        27.08.2024 09:41
        +1

        Не вижу в этом никакой проблемы.
        1) Используйте внутри блока ссылку, тогда перемещение не произойдет.
        2) В коде, который возможно не исполнится, вызывайте `.clone()`, если вам нужно владение.
        Такой подход будет оптимальным и с точки зрения быстродействия, и читаемости кода.


    1. holymoses
      27.08.2024 09:41

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


  1. bvvbvv
    27.08.2024 09:41

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


    1. bvvbvv
      27.08.2024 09:41
      +3

      Может быть, все VM для Python и C/C++ перегружены, а для Rust - нет?


    1. domix32
      27.08.2024 09:41
      +2

      Насколько я понимаю память считается вместе с виртуалкой/докером, на которой запускается С/С++. Она же даёт какой-то оверхед на рантайм. Минимальный размер по памяти у С++ в районе 10 мб. На некоторых задачах видел ~8, но никогда меньше. У раста минимальный рантайм отъедает примерно 2 мб.

      А так - если алгоритмы написаны одинаково на Rust и на C/C++, то рантайм на литкоде будет различаться на пару миллисекунд. Судя по отъедаемой памяти - код не был эквивалентен.

      Ещё один нюанс - автовекторизация. С/С++ используют два компилятора - gcc и clang. rust только clang. Поэтому велик шанс, что у раста сгенерировались векторные вставки, а у плюсов - нет.

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

      auto gucciGang = []() {
        std::ios::sync_with_stdio(false);
        cin.tie(nullptr);
        cout.tie(nullptr);
        return 0;
      }();

      Но похоже в какой-то момент они это прописали где-то в своём бойлерплейте и трюк больше не добавляет ускорение. Повторные ресабмишны С++, кстати, примерно по той же причине могут отдать сильно иные цифры.


  1. menelion_elensule
    27.08.2024 09:41
    +3

    А что скажете по поводу Zig? Вроде как тоже претендент на замену Плюсов.


    1. voidinvader
      27.08.2024 09:41
      +3

      Впервые слышу про этот язык, но надеюсь, что среда его исполнения называется не Hile.


    1. Refridgerator
      27.08.2024 09:41
      +2

      Это претендент на замену просто си, без плюсов.


  1. domix32
    27.08.2024 09:41
    +6

    После коронавируса (в рамках реструктуризации) Mozilla стала увольнять сотрудников,

    насколько мне известно сокращения начались раньше из-за сокращения финансирования из-за того что гугл вляпался в антимонопольную историю и сократил плату за дефолтный поисковик в браузере.

    Более того, с 2021 года Google теперь поддерживает Rust в разработке приложений для Android наравне с C/C++.

    А есть ссылка? Насколько мне изестно официальная поддержка раст только в проекте Fuchsia - операционная система для IoT-like устройств. Ну и в кодовой базе появилось несколько переписанных модулей, имевших застарелые проблемы безопасности, связанные с памятью, в частности bluetooth модуль.

    Из-за закрытости платформ Apple язык Swift подойдет только для:

    Там недавно вроде кроссплатформенность какую-то базовую завезли.

    Кстати синтаксис Carbon очень похож на синтаксис Rust,

    Он похож скорее на D, чем на Rust. И вероятно имеет такие же успехи стать заменой С++ как и D.

    Более вероятными "убийцами" С++ могут стать Zig, CppFront и Odin.

    Zig во многом похож на Go, однако не имеет сборки мусора и в среднем находится где-то между Си и Go.

    CppFront - фактически C++ без легаси - то как язык должен был бы выглядеть, если бы не бремя легаси - консистентный синтаксис вместо спирали смерти C/C++, нормальные дефолты, сокращение бойлерплейта, адекватные ошибки, современные фишки, полная обратная совместимость с С++. Фактически оно всё это конвертит в тот же С++ активно обмазывая это кусками GSL, как в своё время он это делал с С++, конвертируя его в С.

    Odin - ещё один С-подобный язык, во многом синтактически похожий на Go и Zig. Целью языка был лаконичный и быстрый компилятор - по заветам Джона Блоу - который можно было бы также легко написать как и компилятор Си. Синтаксис языка устроен таким образом, чтобы его рефакторинг происходил как можно проще и эволюция программы от этого страдала меньше. При этом сборочная система языка требует только компилятор этого самого языка, что опять же отлично сказывается на экосистеме.

    Zig и Odin топят за ручное управление памятью, но с синтаксическим сахаром, что делает их на порядок безопаснее того же Си и C++, при том что по производительности они не уступают. У обоих имеется свой вариант Tagged Union (в Rust они представлены как enum), что также облегчает работу со многим вещами, такими как машины состояний. Ну и кажется у обоих имеется рефлексия на уровне языка.


  1. AnROm
    27.08.2024 09:41
    +9

    Можно писать сколько угодно статей "Язык Х - убийца C++", но уже написанный C++ код никто полностью переписывать не будет, это потребует много времени и денег. Да и после реанимации языка, начиная со стандарта C++09, все не так плохо.


    1. DarkTranquillity
      27.08.2024 09:41
      +13

      Я например просто устал от этих растаманов и прочих, которые не осилили плюсы.

      Они все еще живут в страхе от new/delete, которые, как сказали выше, уже давно практически моветон.

      Зато жутко уродский синтаксис ржавого никого не смущает.


      1. BenGunn
        27.08.2024 09:41
        +8

        Бро, про синтаксис прямо в точку. Мне иногда кажется, что Rust синтаксис был придуман как бунт против плюсов. Главное что бы не так как у них.


    1. 0x00fe
      27.08.2024 09:41

      нету такого стандарта


      1. DarkTranquillity
        27.08.2024 09:41

        Очевидно, что речь про 11


  1. rukhi7
    27.08.2024 09:41

    А вставки на Ассемблере или целые функции какая-нибудь из предлагаемых замен позволяет писать?

    Тема осталась не раскрытой.


    1. 0x6b73ca
      27.08.2024 09:41

      https://doc.rust-lang.org/reference/inline-assembly.html


    1. codecity
      27.08.2024 09:41

      А вставки на Ассемблере или целые функции какая-нибудь из предлагаемых замен позволяет писать?

      А вот с C++ это работает не везде. Так, начиная с Visual Studio 2022, Microsoft больше не поддерживает ассемблерные вставки (inline assembly) в компиляторе Visual C++ при компиляции с использованием режима x64 (64-битного кода).


      1. firehacker
        27.08.2024 09:41
        +1

        Я бы огорчился но понял, если бы они вообще запретили инлайн асм в С++. Но почему запрещён имено x64-асм, а другие не запрещены я даже понять не могу.


  1. firehacker
    27.08.2024 09:41
    +10

    C++, выглядит громоздким и архаичным

    Что за субстанция в голове у людей, которые вот так искренне считают...

    fn funcname() -> rettype

    Вместо

    rettype funcname()

    И эти люди смеют заикаться о громоздкости... Что касается архаичного, якобы, внешнего вида, то это чистой воды NIH-синдром и юношеское революционерство, желание стать Страуструпом 21-го века и дистанцироваться от предыдущих поколений.


    1. BenGunn
      27.08.2024 09:41

      На плюсах тоже можно так писать нынче. Просто бойзы не в курсе что так можно :)


      1. Melirius
        27.08.2024 09:41
        +3

        Там не fn, там auto - на целых две буквы больше!


    1. qwerty19106
      27.08.2024 09:41
      +6

      Передача аргументом указателя на функцию в С и С++ - громоздкая и архаичная. Например это очень сложно читать:
      int operation(int(*op)(int,int), int a, int b) { return op(a, b); }

      А вот это сразу очевидно:
      fn operation(op: fn(int, int), a: int, b: int): int { return op(a, b); }


      1. mk2
        27.08.2024 09:41

        Да, этот C синтаксис указателей не очень. Зато C++11: std::function<int(int, int)> - разве не очевидно? Заодно можно и лямбду передать.

        А в вашем растовом примере мне наоборот совершенно неочевидно, а где возвращаемый тип аргумента op? Или можно передать с любым, главное чтобы аргументы совпадали?


        1. qwerty19106
          27.08.2024 09:41

          Вы правы, тип я забыл указать. Должно быть так:
          fn operation(op: fn(int, int): int, a: int, b: int): int { return op(a, b); }

          Или можно передать с любым, главное чтобы аргументы совпадали?

          Зависит от задачи. Если тип не указан, то ничего не возвращается (аналогично void в С и С++)


      1. firehacker
        27.08.2024 09:41

        А что делать, если мне не сложно читать первую запись? Куда обратиться? А вот вторая запись, напротив, вызывает вопросы.

        Во-втором примере я не вижу, куда спряталась информация о типе возврата функции, указатель на которую передаётся. Или функции operation пофигу: она ждёт указатель на функцию, принимающую два инта, а что она там возвращает ей глубоко наплевать? И как в этой нотации записать не указатель на функцию, а указатель на указатель на функцию, или указатель на указатель на указатель на функцию?


        1. qwerty19106
          27.08.2024 09:41

          Во-втором примере я не вижу, куда спряталась информация о типе возврата функции, указатель на которую передаётся.

          Я чуть выше уже про это ответил.

          И как в этой нотации записать не указатель на функцию, а указатель на указатель на функцию, или указатель на указатель на указатель на функцию?

          Точно также, как в С, но читается лучше:

          op_ref_ref_ref: &mut &mut &mut fn(int, int): int

          Разумеется могут возникнуть проблемы с Borrow Checker в такой схеме, так что лучше

          op_ref_ref_ref: &mut Box<Box<Box<fn(int, int): int>>>

          Хотя я не могу даже представить, зачем нужно передавать "указатель на указатель на указатель на функцию".


    1. AbitLogic
      27.08.2024 09:41

      Допустим мне нужна функция, принимающая 7 параметров типа const unsigned long int, как это будет выглядеть в С++? В Паскале к примеру F(const a,b,c,d,e,f,g:Dword)


    1. 0x1b6e6
      27.08.2024 09:41
      +4

      Все относительно:

      template<typename T>
      void func(const T &value);
      

      vs

      fn func<T>(value: &T);
      


    1. TheDreamsWind
      27.08.2024 09:41
      +2

      Мне и весь этот хайп с небезопасностью плюсов непонятен: если "программист" не умеет писать безопасный C++ - это в общем-то означает, что он просто не умеет писать на C++


  1. NeoCode
    27.08.2024 09:41
    +5

    Обратная совместимость. Код C++ можно включать в файлы Carbon. 

    Вот это очень важно. Чтобы прямо в рамках одного проекта работало - старое можно до поры до времени (или навсегда) оставить на С++, новое писать на новом языке. И чтобы все среды разработки из коробки поддерживали такие гибридные проекты.

    Собственно, и в рамках самого С++ можно было бы так сделать - развитие текущего С++ заморозить навсегда, выпустить некую очередную версию языка без всех костылей и легаси, несовместимую со старым кодом, назвать это С++2, старый код от нового отличать за счет другого расширения файла или #pragma version 2 в начале файла. Но чтобы можно было легко собирать гибридные проекты. Тогда у разработчиков будет стимул постепенно переходить на новый язык, новые проекты сразу на новом, в старых - добавлять новые файлы на новом языке и переписывать старый код лишь по мере необходимости (или вообще не переписывать, если таковой необходимости нет).


    1. BenGunn
      27.08.2024 09:41

      Не нравится старый стиль - не используй! У тебя есть древний код из эпохи древних стандартов или вообще некросишный код? Напиши враперы и юзай современные плюсы и даже новый язык придумывать не надо. Считаю, что у плюсов три серьезный минуса - это медленная сборка, распространение кода(надо запарится, что бы какую нибудь либу слинковать с проектом) и системы сборки которое шо то шо это. Одинаковое г-но.


    1. firehacker
      27.08.2024 09:41
      +1

      И чтобы все среды разработки из коробки поддерживали такие гибридные проекты.

      В смысле, среды? Какие вам среды нужны?

      Писать проект на двух или более языках всегда было возможно, и эта возможность всегда упиралась в линкер, а не IDE или один из ЯП. Если линкер способен слинковать объектные файлы, порождённые разными компиляторов разных ЯП — милости просим.

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


  1. codecity
    27.08.2024 09:41
    +2

    По итогу - надежды на Carbon. А так пока ничего толкового нет.

    Теперича C++ уже не тот, что давеча. Неудобства конечно есть, но не так чтобы сильно критичные.


  1. Basheyev
    27.08.2024 09:41
    +2

    У каждого языка своя ниша. Rust и Golang сравнивать с C++ некорректно, они не то что не мультипарадигменные, они даже не ООП. Rust - больше альтернатива C.

    Реальной альтернативой C++ мог бы стать Dlang, но к сожалению за ним не стоят корпорации и о нём мало кто знает. На мой взгляд гораздо стройнее Carbon, Swift.

    https://dlang.org/


    1. Anarchist
      27.08.2024 09:41
      +1

      Rust очень даже ООП. Чего не хватает в нем, чтобы быть ООП?


  1. Refridgerator
    27.08.2024 09:41
    +3

    Carbon — это абсолютно новый (он появился в 2022 году) компилируемый язык общего назначения от компании Google, который позиционируется как более синтаксически элегантный преемник C++.

    Любой язык, который позиционируется как "убийца с++" обречён на провал. Потому что народу не нужен убийца чего-либо. Народу нужен удобный инструмент для работы. Это когда например увидел первый раз C# - и дельфи с джавой тут же стали пережитком прошлом.

    А на Carbon я посмотрел ещё 2 года назад - ну не увидел никаких инноваций, чтобы с++ тут же стал пережитком прошлого (как случилось в своё время с дельфями). Увидел солянку из кучи всего от других языков. Более того, авторы не стеснялись говорить «присылайте нам свои идеи» - ну то есть взялись за разработку нового революционного языка не имея достаточного количества идей о том, а чем же он будем качественно превосходить все прочие уже существующие языки.


  1. dv0ich
    27.08.2024 09:41
    +4

    Централизованная экосистема - это сразу до свиданья. Не хватало ещё на уровне ЯП столкнуться с тем, что очередные чепушилы посчитали тебя человеком второго сорта и перекрыли доступ.

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

    У плюсового rettype funcname() тоже есть недостаток: если возвращаемый тип довольно длинный, то код начинает плохо считываться, но это решается использованием для таких случаев схемы auto funcname() -> rettype.

    Ну и в целом синтаксис того же Rust это что-то с чем-то. Создатели явно хотели сделать ещё хуже, чем у С++. Неприятно даже смотреть на исходники, какая-то каша.

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

    Да, у С++ есть весьма серьёзный минус: системы сборки. Но вот эти вот мягкие кресла, предлагаемые новомодными язычками, могут в один прекрасный момент превратиться в стул ведьмы. Спасибо, уж лучше я как-нибудь поживу с табуреткой cmake.


    1. nikitakim
      27.08.2024 09:41

      То есть auto funcname() -> rettype лучше чем fn funcname() -> rettype?)


      1. dv0ich
        27.08.2024 09:41

        Лучше, конечно. Потому что оно, во-первых, опционально, во-вторых - про двухбуквенные слова я писал выше.


    1. NeoCode
      27.08.2024 09:41
      +1

      Ключевое слово fn это рак мозга и паскальная живопись.

      Нет, ключевое слово fn (а также fun, func, function) это необходимость для упрощения компилятора, чтобы не было всяких Most Vexing Parse (а короткие ключевые слова действиительно удобнее для написания). А вот что действительно рак мозга и паскальная живопись - так это мусорные стрелочки и двоеточия при объявлении функций и переменных, которые выполняют чисто декоративную роль и визуально засоряют код.

      function Add(x, y: Integer): Integer;       // Pascal
      fn add(x: i32, y: i32) -> i32               // Rust
      fn Add(a: i64, b: i64) -> i64               // Carbon
      func greet(name: String) -> String          // Swift
      def greet(name: String, age: Int): String = // Scala
      fun greet(name: String, age: Int): String   // Kotlin
      fn add(x: i32, y: i32) i32                  // Zig

      В языке Go нет никаких стрелочек и двоеточий, и никаких проблем их отсутствие не создает.

      func sum(x, y int) int                      // Go


      1. dv0ich
        27.08.2024 09:41

        Нет, ключевое слово fn (а также fun, func, function) это необходимость для упрощения компилятора, чтобы не было всяких Most Vexing Parse

        Ок, принимается.

        а короткие ключевые слова действиительно удобнее для написания

        Для написания, да. Но не для чтения. Слово func намного легче считывается.

        Насчёт мусорных двоеточий и стрелочек тоже согласен.


        1. Uint32
          27.08.2024 09:41
          +2

          > Нет, ключевое слово fn (а также fun, func, function) это необходимость для

          > упрощения компилятора, чтобы не было всяких Most Vexing Parse

          Ок, принимается.

          Изменение синтаксиса для упрощения написания компилятора - имхо вообще не аргумент для определения конструкций языка


      1. Refridgerator
        27.08.2024 09:41

        Отсутствие двоеточия не создаёт проблем, если пробел не перегружен. Лично я бы предпочёл избавиться от обязательных скобочек для передачи параметров в функцию, а также от fn/def/var/auto в принципе. Хочу например вместо print(sin(x)) писать просто print sin x . А для объявления функции использовать какой-нибудь символ, а не ключевое слово, например

        #AddSub (a,b):int -> (c,d):int
        c=a+b
        d=a-b

        Почему стрелочка вам код засоряет, а ключевое слово func - нет?


        1. NeoCode
          27.08.2024 09:41

          Потому что ключевое слово func стоит в начале всей конструкции. Значит, все что дальше - функция. Также как struct - структура, enum - перечисление, и т.д. Первое слово всегда определяет языковую конструкцию.

          И кстати, еще одно преимущество синтаксиса Go - в том, что в нем лямбда-функции объявляются в точности также как и "обычные". Т.е. вообще никакой разницы, только имя не указывается. В остальных же языках - зоопарк кто во что горазд. Какие-то вертикальные палки и прочий ужас.

          [](int x, int y) { return x+y; };           // C++
          ^int (int x, int y) { return a + b; };      // ObjC
          (x, y) => x + y                             // C#
          (int x, int y) -> x + y                     // Java
          delegate int(int x, int y) {return x+y;}    // D
          let add = |a, b| a + b;                     // Rust
          { (a: Int, b: Int) -> Int in return a + b } // Swift
          (a: Int, b: Int) => a + b                   // Scala
          _ + _                                       // и это тоже Scala
          { x: Int, y: Int -> x + y }                 // Kotlin
          lambda x, y: x + y                          // Python
          lambda { |x, y| x + y }                     // Ruby
          (x, y: int) => x + y                        // Nim
          |x: i32, y: i32| i32 { return x + y; };     // Zig

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


          1. Refridgerator
            27.08.2024 09:41

            Потому что ключевое слово func стоит в начале всей конструкции.

            Почему бы и определение типа не делать тоже слева, как в с++? Я не вижу удобство в том, когда какие-то определения/типы/ключевые слева, а какие-то справа. Лично мне нравится когда всё справа, но до логического конца этого ещё никто не довёл. В том же карбоне пока ещё не догадались, что вариант x=5:int более читабелен, чем x:int=5.

            В остальных же языках - зоопарк кто во что горазд. Какие-то вертикальные палки и прочий ужас.

            Ну так если всё будет по-одинаковому - то и языки друг от друга не будут отличаться.

            И вообще в ASCII операторных символов мало (а в языках программирования используется именно ASCII потому что эти символы гарантированно есть на всех клавиатурах мира)

            Так вроде давно уже все на юникод перешли. Повесить дополнительные символы на клавиатуру не проблема как глобально, так и локально (через автозамену в IDE, типа "?*" на "×", "?/" на "÷" и тд).


        1. Uint32
          27.08.2024 09:41

          Не факт, что множество вариантов вызова функций (со скобками и без) это хорошо.
          Как, например, без скобок выразить print(sin(x) + cos(x)) ?


          1. Refridgerator
            27.08.2024 09:41

            Если прям совсем без скобок - то используя постфиксную запись, типа как в Вольфраме: sin x + cos x >> print (а конкретно в Вольфраме это будет как Sin[x]+Cos[x] // Print). В порядке эксперимента и проверки концепции бесскобочный парсер (а заодно и неявное умножение) я уже делал, поэтому это точно возможно. Насколько такой подход интересен кому-то другому - вопрос уже другой, но математики в своей массе скобочки после функций без необходимости не ставят.


          1. unC0Rr
            27.08.2024 09:41
            +1

            Вот Хаскель, к примеру:

            Prelude> let x = 1
            Prelude> print $ sin x + cos x
            1.3817732906760363
            Prelude> print (sin x + cos x)
            1.3817732906760363


        1. bolk
          27.08.2024 09:41

          $x = 10;
          print sin $x;
          # -0.54402111088937

          Такое есть в Перле ))


  1. leon0399
    27.08.2024 09:41

    C++ и PHP — два языка которые «вот-вот» уже должны умеритесь и надо их заменять. Но только они никак не умирают, а наоборот, только развиваются. Так может пора перестать искать «новых убийц», а применять различные технологии там, где это необходимо, без попыток сделать «X, только лудше!»?


    1. codecity
      27.08.2024 09:41

      PHP

      Ну вроде как большая часть PHP-шников частично или полностью перешли на Python, откуда и взрывной рост оного. Тем более что языки весьма похожи, можно сказать что разница не значительна, но Python имеет во много крат более развитую инфраструктуру (библиотеки и пр.).


      1. bolk
        27.08.2024 09:41

        Туда перешли ML-щики, а не пхпшники. У пхп лучше с типизацией и скоростью.


  1. andres1
    27.08.2024 09:41
    +2

    Я не понимаю одного. Зачем менять синтатксис языка? Чтоб отличаться?

    А уж невозможность в Котлине использовать в индексах массивов числа с плавающей точкой меня убило (при пяти новых вариантах написания цикла for).


  1. rutexd
    27.08.2024 09:41
    +1

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


    1. Anarchist
      27.08.2024 09:41
      +1

      Это как ботинки из цемента :)
      Мне кажется, что языки типа C, C++, Java сильно отстали от поезда. Будущее за языками, способными интероперировать с ними - Rust, Kotlin, Scala. Иначе вляпаемся в очередную коболу :)


  1. 0xC0CAC01A
    27.08.2024 09:41
    +2

    А что случилось с Go, что Гугл, его авторы решили ещё один язык придумать на замену?


  1. siberianlaika
    27.08.2024 09:41

    Опять заменять C++ и убивать С? Я думал уже успокоились и больше не надо точить ножи :|
    Я вообще сам на Go программирую, уже > 10 лет как, и мне очевидно, что никакого C++ он заменять не собирается и не собирался. Когда-то на заре создания языка авторы хайпа ради высказались, что это может стать заменой C++, но быстро стало понятно, что в этом нет резона. У Go своя ниша написания многопоточных сервисов, где он отлично смотрится на фоне других языков, также в принципе он неплохо подходит для написания GUI (хотя в этой области малопопулярен). Если он кого и вытеснял, то уменьшил количество вебсервисов на PHP, Ruby и Python, и то вывести их полностью вероятно невозможно.