Rust превосходит по производительности C++ согласно результатам Benchmarks Game

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

    image

    Для сравнения производительности используется геометрическое среднее времени выполнения 10 различных программ. Согласно последним результатам Rust превзошел С++ в 6 задачах из 10.

    Под катом некоторое детали и мнение о дальнейших перспективах.

    Как правильно интерпретировать результаты?


    Benchmarks Game — популярный проект, в котором языки программирования сравниваются на основании измерений производительности написанных сообществом программ, решающих поставленные задачи. Как правило, для каждой задачи существует как минимум несколько хорошо оптимизированных реализаций на одном и том же языке. Для подведения общих итогов выбирается только одна реализация для каждого языка, показавшая наилучший результат.

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

    Но ведь бенчмарки ничего не значат!


    И да, и нет.

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

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

    Общий вывод, который следует сделать: при выборе между Rust и С++ производительность языков больше не может быть причиной отдать предпочтение С++. По крайней мере, без проведения дополнительных тестов.

    Может ли текущая ситуация измениться?


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

    Стоит ли ожидать дальнейшего улучшения производительности Rust?


    Да. Компилятор Rust — относительно молодой проект, и значительное количество возможных оптимизаций еще просто не реализовано полноценным образом. Основной преградой является LLVM, который формально хоть и является универсальным транслятором, на практике хорошо оптимизирован для C/C++, и не очень хорошо справляется с байт-кодом (IR), полученным из других языков программирования.

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

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

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

    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

    Сможет ли Rust в ближайшие несколько лет превзойти по производительности C?

    • 51,6%Да271
    • 48,4%Нет254
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 281

      +9
      Я склонен верить, что в большом количестве сценариев у Rust есть преимущество в плане возможности проведения различных оптимизаций, потому что это memory-safe язык. Насколько я понимаю, оптимизаторы Си сильно ограничены из-за того, что в языке есть арифметика указателей и не всегда можно однозначно сказать, используется ли какой-то определенный фрагмент памяти или нет (strict aliasing?).
        +5

        Да но в расте это не включено везде, потому что llvm ломается

          0

          А что ещё осталось включить?

            0

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


            Можно и щас включить через флаг, но на свой страх и риск.

            –4
            Я склонен верить, что в большом количестве сценариев у Rust есть преимущество в плане возможности проведения различных оптимизаций, потому что это memory-safe язык

            безопасность памяти ортогональна производительности. Ну, за исключением того факта, что безопасное подмножество раста попросту не позволит делать некоторые оптимизации.
              +10
              Наоборот: безопасное подмножество rust как раз позволит компилятору делать некоторые оптимизации.

              Простейший пример:
                foo(int& x, int& y, int[] z) {
                  ...
                  x = y;
                  ...
                }
              


              Компилятор C++ обязан в этом месте читать из памяти и писать в память — потому что он не знает объекты x и y — это один объект или это разные объекты… а может один из них — это ещё и элемент массива?

              В Rust вся эта информация доступна не только программисту, но и ком пилятору и он может её использовать… однако пока что он использует её плохо, да ещё иногда и генерит нееправильный код — потому в стабильной ветке Rust подобные оптимизации отключены.
                –1
                "некоторые оптимизации", про которые написал я, это не те "некоторые оптимизации", про которые написали вы. Потому и "некоторые"
                  –4

                  Используйте в С/С++ restrict и будет вам счастье.

                    +2

                    Как было сказано выше, в гцц и ллвм есть баги с restrict: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87609 и https://bugs.llvm.org/show_bug.cgi?id=39282. Нашли баги из-за раста, в котором этот restrict раньше подставлялся автоматически для каждой &mut ссылки. Сейчас из-за баги не подставляется, ждут фиксов в ллвм, чтобы потом опять включить эту оптимизацию.


                    А вы дальше советуйте restrict. Пусть люди стреляют себе в ногу.

              +2
              Язык с ручным управлением памятью быстрее, чем язык с автоматическим при прочих равных. Ваш К.О.

              Хотя немножечко неточно — тесты не при прочих равных, т.к g++ != LLVM, надо было сравнивать одинаковый тулчейн.
                +2
                Ну по поводу автоматического управления памятью в раст, спорный вопрос.
                  –1
                  в расте — ручное, в с++ arc
                    +1

                    Позиция одного из ключевых разработчиков раста (и автора The Rust Programming Language) — в расте статический GC.

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

                      Потому что языки, «разрывающие циклы» — платят за это высокую цену. Как мне кажется… слишком высокую цену.

                      Потому что в таких языках вы не знаете когда и как вы будете «платить» за выделение и освобождение памяти, можете только догадываться — опираясь на конкретную реализацию GC конкретно вот в конкретной версии вашего runtime. А завтра — всё может быть совсем по-другому.

                      О том что это важно можно заметить по количеству статей, посвящённой этому вопросу на Хабре (да и на любом сайте где обсуждается C#, Java, JavaScript и тому подобные языки). Рано или поздно об этом приходится задумываться всем, кто на этих языках работает.

                      А вот при обсуждении C++ тонкости общения с jemalloc'ом или tcmalloc'ом итересуют очень малый процент разработчиков… потому что если вы не пытаетесь «разрывать циклы», то вы всё ещё не можете сказать точно какую цену вы заплатите за выделение и освобождение памяти… зато можете сказать точно — когда эта цена будет нулевой… и оказывается что для 99.99% случаев на практике — этого достаточно.
                        +1
                        Что значит разрывать циклы? break и continue?
                          +5

                          Речь про циклические зависимости. Например:


                          void Foo() 
                          {
                            var a1 = new A();
                            var a2 = new A();
                            a1.Next = a2;
                            a2.Next = a1;
                          }

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

                            0
                            Поправка «если неправильно использовать рефкаунтинг» — но да, все возможно, компилятор не спасет. Верно так.
                              –1

                              То есть это правильное использование рефкаунтинга? Почему тогда вот этот код падает? https://repl.it/@Pzixel/AcceptableInsidiousUsernames

                                –1
                                Как вы увидели, что код по вашей ссылке падает, если он даже не собирается.
                                  –1
                                  Потому что не Раст. ЛОЛ

                                  Я проверил верно исправленный — не падает.

                                  Посмеялся, глядя на процесс правок. Нет чтобы учебники читать, всё критикуют…
                                  cout << (x->Next).lock()->Value;
                                  так нельзя, lock() может вернуть nullptr
                                    +2

                                    Спасибо, поправил.




                                    Основная идея тут не в том, что я не умею проверять что weak_ptr.lock() вернул нулл, а в том, что структура данных именно что должна владеть данными, а не просто ссылаться. В некоторых случаях типа деревьев weak_ptr может помочь, но и в расте точно так же получится Weak использовать.


                                    Речь про полноценный ГЦ была именно в том что разработчику там не надо забивать себе голову — он всегда делает сильную ссылку, а с циклом разберется рантайм. И это действительно помогает. А еще это помогает делать структуры вроде "массив и ссылка на первый элемент". Self-referential structures огромная морока в расте, для которой целый Pin изобрели, в плюсах я не слышал ни про какое известное решение, а в языках с ГЦ это вообще не проблема.




                                    так нельзя, lock() может вернуть nullptr

                                    Ну вот, так и знал что мне про это напишут...

                                      –1
                                      :) Ну да, поскольку тут владение a2 по сути отсутствует (weak_ptr не дает владения), то в момент завершения Foo() для него вызовется деструктор, expired() для соответствующего weak_ptr вернет true, а lock() вернет nullptr.

                                      P.S. Честно говоря, рефкаунтинг сам по себе и не способен бороться с циклическими зависимостями. Поэтому в питончике вдобавок к рефкаунтингу добавили (отключаемый) gc.
                                        +2
                                        Поэтому в питончике вдобавок к рефкаунтингу добавили (отключаемый) gc.
                                        В третьей версии вроде как уже неотключаемый.

                                        Но споры на тему «а насколько это нужно» будут вечными. Потому что тут речь же не о теоретической оценке чего либо, а о том «насколько сложно руками разрывать циклы» в сравнении с «насколько сложно бороться с GC, который, внезапно, начинает собирать мусор тогда, когда нам это невыгодно».

                                        С учётом того, что одна из самых популярных в мире платформ (iOS) обходится без «полноценного GC»… похоже что Rust идёт в верном направлении…
                          +2
                          Стив Клабник не совсем ключевой разработчик — он главный в команде документации. Хорошо знает, как устроен GC, Patric Walton, но он пишет в основном в твиттере ссылка
                        0
                        что подразумевается под «автоматическим управлением памятью»?
                          +9
                          Язык с ручным управлением памятью быстрее, чем язык с автоматическим при прочих равных. Ваш К.О.
                          Вот только прочие — неравные. Ваш К.О.

                          Собственно многие программы до сих пор написаны на Fortran, потому что аналогичные же программы на C++ — медленнее. А медленнее они как раз потому что «Язык с ручным управлением памятью» — не всегда быстрее.

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

                          P.S. И да: тут как раз вопрос лежит в практической плоскости. Теоретически любую программу на Fortran вдумчивой работой с типами и restrict можно довести до более быстрой программы на C++. А вот практически — у реально существующих разработчиков — это не выходит… Такие дела.
                            –5
                            В С++ применяется ARC — еще раз, это Automatic Reference Counting. Я не понимаю, почему в противопоставлении вы пишете, что С++ — с ручным управлением %-)

                            И кстати, я немного отстал от жизни и не помню наличия работы с хипом в Фортране.
                              0
                              UPD. В Фортране95 есть ручное управление памятью операторами ALLOCATE, DEALLOCATE.
                              Собственно тезис строго наоборот.
                                +1

                                unique_ptr — вовсе не подсчет ссылок. shared_ptr — это подсчет ссылок. Но в хорошей кодовой базе его почти не должно быть. Он в идеале нужен только для shared ownership (внезапно), а оно нужно очень редко.

                                  +1

                                  К слову, обычно буква a в arc означает atomic

                                    –4
                                    К слову, иногда лучше жевать.
                                    shared_ptr не атомарный счетчик ссылок
                                      0

                                      В блоке управления он вполне себе атомарный


                                      Note that the control block of a shared_ptr is thread-safe: different std::shared_ptr objects can be accessed using mutable operations, such as operator= or reset, simultaneously by multiple threads, even when these instances are copies, and share the same control block internally.
                                      +6
                                      shared_ptr содержит атомарный счетчик в контрольном блоке. Точнее, целых два атомарных счетчика — отдельно для weak и strong ссылок. Так что время жизни разделенного объекта, как и время жизни контрольного блока, корректно обрабатывается в многопоточке*. Доступ к самому объекту при этом не является потокобезопасным.

                                      *За исключением юзкейса, когда два потока пытается без синхронизации менять один и тот же инстанс shared_ptr. Тогда реальное число инстансов может рассинхронизироваться со значениями счетчиков. Для этого существует набор атомарных операций над shared_ptr, а также в стандарте будет std::atomic_shared_ptr.

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

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

                                    В Rust же все ограничения заложены в язык, попадают в IR и далее в оптимизатор… где они, в настоящее время, особо не используются, так как оптимизатор заточен, в первую очередь, под C/C++.
                                      –3
                                      С++ прекрасно проверяется линтерами, которые знают про стандартную библиотеку (она же часть Стандарта), и например простой пример — gcc проверяет строку формата printf, хотя теоретически тоже не должен ничего знать.

                                      Так что насчет неверного утверждения про Фортран? Пока что оно подтверждает моё
                                        0
                                        Пока что оно подтверждает моё
                                        Не очень понимаю о чём вы там говорите.

                                        Так что насчет неверного утверждения про Фортран?
                                        А что там с фортраном не так? SciPy уже без него собиратеся? Нет? Ну значит пока — реально существующий код написанный на Fortran всё ещё быстрее реально существующего кода, написаного на C++.

                                        То что в Fortran «сливает» в Benchmak Game — это нормально: это достаточно ограниченный язык, некоторые алгоритмы на него ложатся плохо. Однако в своей области компетенции — он быстрейший… о чём, собственно, и речь.

                                        Rust претендует на то, что будет быстрее C/C++, но при этом ещё и всегда, а не только при работе с матрицами, как Fortran… поживём, увидим.
                                          –3
                                          Язык с ручным управлением памятью быстрее
                                          Фортран с ручным, C++ с автоматическим. Мое утверждение тут не противоречит вашему.
                                            +2

                                            С++ язык с автоматическим управлением? Простите, но — нет.

                                              +4
                                              Ну если у вас C++ стал языком с автоматическим управлением памяти, то что-либо обсуждать становится бессмысленно.
                                            +5
                                            С++ прекрасно проверяется линтерами, которые знают про стандартную библиотеку

                                            Может, вы знаете про какие-то секретные линтеры, но в моём опыте ни coverity, ни clang'овский анализатор, ни даже PVS (хотя он хуже всех себя проявил) не способны найти всего того, что может найти адекватная система типов.


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

                                              0
                                              Конечно так. Поздновато от С++ требовать идеала =)

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

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

                                                С точки зрения компилятора C++ — это язык с ручным управлением памяти. А Fortran, опять-таки, с точки зрения компилятора — язык с ручным управлением памяти (то, что вы назвали «отсутствие работы с хипом», как раз).
                                                  –2
                                                  Кажется я начинаю понимать… Но тут не раст и не ява, которые имеют исключительно свою точку зрения.

                                                  Я предпочитаю иметь свою т.зр. в своих программах:
                                                  1. Использую new/delete — ручное управление
                                                  2. Использую unique_ptr — RAII
                                                  3. Выбираю shared/weak_ptr — ARC
                                                  4. Подключаю boehm — оппа — программа с GC
                                                  5. Беру в расход только автоматическую и статическую память — вообще красота — никаких нежданок, никакого управления…

                                                  Ну да, конечно — это мое ручное управление всей подсистемой памяти, компилятор то не знает =)

                                                  Но в современном C++11 и новее рекомендуется таки пп2,3 — которые относятся к автоматическим
                                                    +3
                                                    Ну да, конечно — это мое ручное управление всей подсистемой памяти, компилятор то не знает =)
                                                    Именно так. Это не смешно, а довольно грустно. Например потому, что любая манипуляция с память через указатель на char может, потенциально, изменить значение любой переменной, адрес которой куда-то, когда-то, хоть раз передавался.

                                                    При этом «стрелять» это может самым неожиданным способом. Сравните, например, foo и bar — и подумайте почему случае с bar компилятор смог показать всю свою изворотливость (и развёрнутый цикл и векторизация и вообще всё круто), а вот foo — осталась, фактически, неоптимизированной.

                                                    Но в современном C++11 и новее рекомендуется таки пп2,3 — которые относятся к автоматическим
                                                    Да — это облегчает работу программисту, но… увы и ах — не компилятору. Более того — эти все чудесные обёртки в системной библиотке зачастую усложняют работу компилятору… ну вот простейший (хотя и довольно-таки патологический) пример… внушает, да?

                                                    Именно за счёт этого языки с автоматическим управлением памяти (не путать с трассирующим GC) могут иногда выигрывать у C/C++… а иногда — и довольно-таки заметно выигрывать…
                                                      –1
                                                      При этом «стрелять» это может самым неожиданным способом. Сравните, например, foo и bar — и подумайте почему случае с bar компилятор смог показать всю свою изворотливость (и развёрнутый цикл и векторизация и вообще всё круто), а вот foo — осталась, фактически, неоптимизированной.

                                                      Компилятору можно и подсказать. Ну да, char* в C/C++ — это «особенный» тип, ничего не попишешь. Но средствА есть.
                                                        +2
                                                        СредствА-то есть, но вот только эти многоуровневые системы костылей — честно говоря начинают надоедать.

                                                        Так что если Rust будет показывать сравнимую производительность на идеоматичном коде без специальных забот обо всех этих тонкостях (типа «разворачивания» std::unique_ptr для возврата значения из функции и заворачивания его обратно в std::unique_ptr в месте получения) — то это будет разумный довод в пользу перехода.

                                                        Потому что сейчас ситация такая: на C++ можно сделать так, чтобы твоя программа была максимально быстрой… но умеют делать это один человек из ста — и то требуется много возни и чуть ли не изучение каждой функции в дизассемблере, чтобы не перепутать куда какие костылики и как вбивать… неудобно.
                                                          –1
                                                          Такие «тонкости», как с unique_ptr могут и починить в будущих версиях компилятора. Меня в расте печалит главным образом его упертость в плане «компилятор лучше знает». Да, мне уже на это отвечали, дескать, «чистый код не самоцель», но… тогда получается, что шило меняется на мыло. К тому же мне надо решать задачи, а не писать обертки, и тем более не тешить свой NIH-синдром, занимаясь RIIR, а если что-то где-то надо оптимизировать в узком месте, то средствА всегда найдутся. В общем, я пока не готов.
                                                            +2
                                                            Такие «тонкости», как с unique_ptr могут и починить в будущих версиях компилятора.

                                                            Я думал, что шутки про достаточно умный компилятор — прерогатива ФП-тусовки.

                                                              0
                                                              Ну а чо мы, лысые, что ли. Те же RVO и copy elision же запилили.
                                                                0
                                                                RVO и copy elision не зашиты в стандартах. unique_ptr, увы, зашит.

                                                                А поскольку это затрагивает «священную корову» — обратную совместимость — то шансов на исправление, мягко говоря, немного.
                                                                  0

                                                                  RVO уже зашито.

                                                                    0
                                                                    RVO уже зашито.
                                                                    только потому, что эта оптимизация может влиять на наблюдаемое поведение.
                                                                      0

                                                                      Возможность RVO была зашита всегда, я же говорю о том, что теперь-то оно mandatory.

                                                              0
                                                              Такие «тонкости», как с unique_ptr могут и починить в будущих версиях компилятора.
                                                              Нет, не могут. Это ABI.

                                                              Теоретически можно выпустить новую версию ABI — но шансов на это примерно нуль.

                                                              А в Rust — это не зафиксировано пока в ABI никак и, когда зафиксируют, могут сделать лучше.
                                                                0
                                                                Ну да, пожалуй, не сломав обратной совместимости, этого не починить.
                                                              +2
                                                              типа «разворачивания» std::unique_ptr для возврата значения из функции и заворачивания его обратно в std::unique_ptr в месте получения
                                                              ABI в обе стороны «играет» — сегодня на коне раст, а завтра плюсы. Хотя казалось бы… А еще ABI не имеет значения при инлайнинге функций
                                                              Потому что сейчас ситация такая: на C++ можно сделать так, чтобы твоя программа была максимально быстрой… но умеют делать это один человек из ста
                                                              собственно точно так же и в расте и примерно любом другом ЯП.
                                                                +3
                                                                ABI в обе стороны «играет» — сегодня на коне раст, а завтра плюсы. Хотя казалось бы…
                                                                А что именно «казалось бы»?

                                                                Rust имеено потому и не имеет аналога Itanium C++ ABI, что не хочет, чтобы «замороженный» раз и навсегда ABI приводил к тому, что подобные вещи нельзя было бы исправить.

                                                                А вот у C++ — приоритеты другие.

                                                                Потому «на дальней дистанции» Rust должен бы иметь преимущество.

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

                                                                Core Guidelines прямо говорит: используйте unique_ptr<T> и создавайте эти переменные с помощью make_unique… но на самом-то деле нужно использовать new и возвращать gsl::owner, если мы хотим «эффективности как в C»!

                                                                Вот и интересно понять — насколько реально быстрый код на Rust отличается от «идеоматичного», «рекомендуемого»…
                                                                  0

                                                                  Ну на нашей практике максимально тупой идиоматичный код выдал практически максимальный перфоманс, судя по профайлеру и загрузке процессора. Еще в 2 раза выжали, пройдясь vtune'ом и расставив стратегические префетчи где надо, убрав работу с памятью.


                                                                  И судя по всему, это не у нас одних.


                                                                  Говорить что "думать вообще не надо" не буду, ограничусь "идиоматичный код получается весьма быстрым, иногда быстрее оптимизированного си".

                                                                    –1
                                                                    А что именно «казалось бы»?
                                                                    а вы глянули в мои примеры? Изменение кажется незначительным, но переворачивает всё с ног на голову.
                                                                    Rust имеено потому и не имеет аналога Itanium C++ ABI, что не хочет, чтобы «замороженный» раз и навсегда ABI приводил к тому, что подобные вещи нельзя было бы исправить.

                                                                    Потому «на дальней дистанции» Rust должен бы иметь преимущество.

                                                                    пока rust не стабилизирует ABI, ни о какой «дистанции» речи и быть не может. А дальше будет иметь значение компромиссы какого из ABI лучше применимо к конкретным приложениям.
                                                                      +4
                                                                      пока rust не стабилизирует ABI
                                                                      А почему вы считаете, что он это, вообще, должен делать?

                                                                      Движение вообще в другую сторону идёт: clang умеет отказываться от ABI для static функций, к пример, чтобы быстрее было.
                                                                        0

                                                                        Это и gcc/msvc уже очень давно делает, и не только для статик, но и для всех при lto/pgo. ABI он наружу, чтобы статические либы и dll\so не протухали каждые несколько месяцев.

                                                                          +2
                                                                          ABI он наружу, чтобы статические либы и dll\so не протухали каждые несколько месяцев.
                                                                          Тем не менее C++14 ABI и C++17 ABI несовместим, так что с некоторой частотой это всё равно происходит.

                                                                          Я уже не говорю про разные компиляторы.

                                                                          В общем в отношении Rust'а моё отношение всё ещё немного скептическое… но уже совсем немного…
                                                                            0

                                                                            Ну это да. И это порождает определенные проблемы, из-за этого даже вводят всякие _GLIBCXX_USE_CXX11_ABI, и оно даже реально пригождается в реальной жизни. И вот представим что на это забьют и это все станет регулярным. Раз в 3 месяца пересобираем весь мир, к примеру (а проблем с пересборкой конечно же ни у кого не возникнет). А проприетарщина вообще, кому она нужна? Давайте исходники, либы не принимаем.

                                                                          –1
                                                                          А почему вы считаете, что он это, вообще, должен делать?
                                                                          представьте, что вы хотите поставлять вашу библиотеку без исходников — совершенно адекватный коммерческий юзкейс. И вам наверно захочется чтобы эту библиотеку можно было использовать не только из-под ubuntu 18.1.2 и rustc 1.39.16 на компьютерах с intel i7 8-ого поколения, которым это всё барахло компилируется у вас. Точнее, компилировалось у вас вчера. А сегодня вы обновили компилятор до rustc 1.40.1 (nightly) чтобы посмотреть очередную классную фичу, а еще обновили librustrt.so, и отныне всем вашим клиентам нужно будет воспроизвести эти шаги чтобы работать с вашими новыми библиотеками.
                                                                            +3
                                                                            представьте, что вы хотите поставлять вашу библиотеку без исходников — совершенно адекватный коммерческий юзкейс.
                                                                            Прикрутите к ней API на C — и поставляйте.

                                                                            Попытки «заморозить» C++ ABI показали, что пользоваться этим всё равно умеют единицы, а проблемы это вызывает у всех.
                                                                              0

                                                                              То-есть пользоваться растом исключительно через другой язык? Где таки постарались и нарушения ABI редки?


                                                                              И чем умеют пользоваться, и какие проблемы у всех возникают? C++ ABI умеют пользоваться единицы и у всех с ним проблемы возникают?
                                                                              Ну так а вы предлагаете еще чаще эти проблемы сделать, а пользоваться умеют все — скомпилил и какой-то ABI получил. И его желательно не замечать, только чинить если у кого-то где-то сломается, а не ломать все время. Вот чинить да, может и единицы умеют. Посмотрите как это в firefox решается для stdc++, и это при редких изменениях, а при нестабильном — будет вообще кошмар.


                                                                              Ломать его, конечно, приемлимо в некоторых случаях, например если ни либы ни dll\so не нужны. Но в остальном — чем реже тем лучше.

                                                                                +3
                                                                                Где таки постарались и нарушения ABI редки?
                                                                                Проблема не в том, что «там постарались и нарушения ABI редки», а в том, что если вы делаете «широкий», «быстрый» интерфейс, то сделать его эффективно — очень тяжело. А если у вас там сплошные «хенлы» и внутренняя реализация скрыта — то ничего, кроме того, что предоставляет C — не нужно.

                                                                                Посмотрите как это в firefox решается для stdc++, и это при редких изменениях, а при нестабильном — будет вообще кошмар
                                                                                Три или четыре раза её меняли полностью несовместимым образом. Несколько раз обнаруживали несовместимость и чнили. Заметьте: libstd++ — это библиотека, разработчики которой прилагают титанические усилия для поддержания совместимости — и всё равно, как вы говорите: это проблема.

                                                                                Но в остальном — чем реже тем лучше.
                                                                                Это теория. А на практике — libicu имеет 60 несовместымых версий. Boost — сравнимое число. И это ведь — «золотой стандарт», библиотеки, которыми пользуются огромное количество народу! А в более мелких народ вообще не задумывается о том, чтобы была хоть какая-то совместимость.

                                                                                Если требуется совместимость — то C++ интерфейс всё равно заворачивается в C интерфейс (как в libandroidicu) и потом «с другой стороны» на него снова вешается C++ обёртка.

                                                                                Ну и? Нафига козе баян, все сложности поддержания стабильного ABI — если люди всё равно этим не пользуются? Не проще ли признать, что мы не умеем делать быстрые и стабильные интерфейсы и просто дать возможность разработчикам выбирать?
                                                                                  0

                                                                                  Все так: glibc — мало проблем, libstd++ — больше, Boost — еще больше; libicu — не сталкивался. Но это не значит что им не пользуются.
                                                                                  У steam runtime, например, достаточно стабильное API/ABI, в пределах дистра благодаря этому куча кода шарится, даже у flatpak/snap идут ссылки на свои core для этих целей. Есть куча более стабильных библиотек что таких проблем не вызывают. И это будет еще только больше проблем если весь этот мир пересобирать раз в несколько месяцев.


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


                                                                                  К слову про производительность. Все последние изменения в stdc++ abi они из-за фич языка, не из-за производительности. Производительность да, это хорошо, и над этим думать надо. Но это редко надо, бесконечность итераций тут не надо для одной архитектуры для стабилизации.

                                                                                    +1
                                                                                    Все последние изменения в stdc++ abi они из-за фич языка, не из-за производительности.
                                                                                    Потому что изменения для увеличения производительности потребуют изменить ABI — а он священен.

                                                                                    Но это редко надо
                                                                                    Там где это не нужно — есть Java, Python… и C интерфейс.

                                                                                    У steam runtime, например, достаточно стабильное API/ABI, в пределах дистра благодаря этому куча кода шарится, даже у flatpak/snap идут ссылки на свои core для этих целей.
                                                                                    Если вы всё собираете одним компилятором из неизменных исходников — то не вижу проблем.
                                                                                      0

                                                                                      Проблема тут следующая: Я не собираю игру тем же компилером что steam runtime. И когда пакую ее во flatpak, я не собираю core, но ссылку на него указываю. Понятия не имею, что там за компилер использовался, но игра работает.


                                                                                      Ну то-есть ABI нужен везде, где надо что-то с чем-то совместить, компоненты, где твое может быть только часть. Поставить third party, собрать что-то один раз и использовать либу, сделать dll\so и экономить юзеру память, плагины к какому-то софту итд. Когда все это не надо — ну да, тут эффективнее lto и статическая линковка, ктож спорит.

                                                                                    0
                                                                                    Проблема не в том, что «там постарались и нарушения ABI редки», а в том, что если вы делаете «широкий», «быстрый» интерфейс, то сделать его эффективно — очень тяжело. А если у вас там сплошные «хенлы» и внутренняя реализация скрыта — то ничего, кроме того, что предоставляет C — не нужно.
                                                                                    вы предлагаете даже не пытаться поддерживать совместимость и писать сишные обертки? Вы же должны понимать, что это хуже буквально любой альтернативы?
                                                                                      +3
                                                                                      Это то, что всё равно по итогу делается. Я не знаю ни одной «живой» операционки, предоставляющей из коробки C++ интерфейс хоть к чему-нибудь.

                                                                                      Даже какой-нибудь MFC — он вместе с приложением идёт и вам нужна ровна та версия, которая будет совместима ровно с тем компилятором, которым вы это приложение собираете…
                                                                                        –1

                                                                                        Как это не видели? В винде msvcp*, это хоть и redist и его обычно с приложением поставляют (хотя от старых студий уже вроде в комплекте, от 6й точно), но оно будет шариться между всеми использующими эту стабильную версию приложениями, и ему нужен ABI. Так же directx redist включают, COM интерфейс это тоже не C.


                                                                                        Макось? Полно не сишных интерфейсов, и что печально — сишные opengl и openal депрекейтят.


                                                                                        На лине тоже firefox использует stdc++ из системы, причем там при сборке конфигурится, какую минимально поддерживать. Есть куча других либ с не сишными интерфейсами.


                                                                                        Но вы абсолютно правы, что си интерфейс — наиболее ABI стабильный. А с++ и другие ломаются куда чаще. Именно потому его все любят, когда нужна совместимость. Именно потому — часто ломать ABI плохо, неважно stdc++, rust или go. Это вызывает проблемы в определенных случаях и их придется решать одним из способов.

                                                                                          0
                                                                                          Именно потому — часто ломать ABI плохо, неважно stdc++, rust или go.
                                                                                          И именно поэтому в ядре Linux специально ломают ABI, ага.

                                                                                          Понимаете — мантра «часто ломать плохо» работает, когда альтернатива не слишком сложна. Если же ABI всё равно регулярно ломается — то проще не делать вид, что его можно как-то «застабилизировать», а признать, что его нельзя использовать, если вы два компонента независимо собирать хотите.

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

                                                                                            Вы опять про все пересобрать. Вы понимаете, что если вы можете все пересобрать, — оно вам не надо. А если Far собран С++, а плагин на дельфи, и его создатель не имеет контроля над сборкой фара, и всех его версий у всех, — то ABI нужно. Да, оно кода-нибудь сломается, но ABI тут всё равно нужен, так что обратная мантра тоже не работает. И чем дольше оно не ломается — тем лучше. В вашем варианте мы просто не делаем плагины фару, всегда пересобираем из какой-то репы те что у вас есть.


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

                                                                                              +3
                                                                                              А если Far собран С++, а плагин на дельфи
                                                                                              … то использовать как C++-строки, так и Delphi-строки в ABI вы не можете. И вам придётся, скорее всего, использовать C-style ABI.

                                                                                              И чем дольше оно не ломается — тем лучше.
                                                                                              Конечно. POSIX-api скоро полвека стукнет — а оно всё ещё «не ломается»

                                                                                              Кейсов где ABI нужен полно.
                                                                                              А где я с этим спорил? Продуманный ABI может жить десятилетиями… А вот ABI, который получился у вас, когда вы завели три класса и десять функций, а потом всё это проэкспортировали — нет.

                                                                                              А если вы уже разрабатываете ABI — то его можно и в C-функциях и в GBus, какой-нибудь, превратить… а если о нём не думать — то ничего хорошего не выйдет.
                                                                                                –2

                                                                                                Нет, на винде ABI у дельфи для dll`ок вполне совместим. Ну то есть вы согласны что ABI иногда нужен, и что когда он долго не ломается — это хорошо?
                                                                                                Вы просто к тому что у других языков это не получится и надо всегда делать обертки на си? Ну хорошо, это же не противоречит тому, что ломать ABI плохо. Просто язык значит никогда не будет самостоятельным и требовать си для кейсов когда нужен ABI, именно по этой причине. И чем чаще происходит поломка ABI — тем более это верно.


                                                                                                Вот только не все спешат бежать делать си обертки для своих библиотек. А как миниум С++ и ObjC/Swift в реальной жизни вполне используют. Под виндой какой-то из стабильных msvcp, под линем stdc++ от какой-то версии и получают шаринг между приложениями и приемлимое время жизни приложения.


                                                                                                Отказ от поддержки ABI по сути будет перекладывание работы с разработчика языка на разработчиков библиотек\приложений для кейсов когда он нужен и он никогда не сможет стать именно заменой C/C++.

                                                                                                  +2
                                                                                                  Ну то есть вы согласны что ABI иногда нужен, и что когда он долго не ломается — это хорошо?
                                                                                                  Конечно. Но такой у Rust уже есть.

                                                                                                  Вы просто к тому что у других языков это не получится и надо всегда делать обертки на си?
                                                                                                  Зачем вам «обёртки на си». В C++ есть extern "C", в Rust тоже extern есть.

                                                                                                  Если вы свой ABI продумываете — этого достаточно. А если нет — то у вас и не получится стабильного ABI, даже если в языке он, формально, имеется.
                                                                                                    0

                                                                                                    Ну тут я согласен. Можно тогда язык использовть через си ABI, раз своего нет. Но конкретно у раста это потребует всякие #[repr(C)] и libc::*, а не все это делают. Язык получается не самостоятельный и это все равно минус. Свой стабильный ABI — это хорошо, или сделать чтобы все нужные конструкции типа #[repr(C)] были автоматом при экспорте в либы\dll\so. Но постойте-ка, это и получился бы совой стабильный ABI.


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

                                                                                                      0
                                                                                                      А иначе — все таки перекладывание этой проблемы с языка на разработчика.
                                                                                                      А стабильный API без разработчика никак не сделать.

                                                                                                      Простейший пример прям из жизни: работаете вы с Xml и назвали вы детей childs (не native speaker, бывает). Потом, в следующей версии, пришёл грамматей и поправил. Стало вместо childs, как и положено childred.

                                                                                                      И? Как вы эту проблему на уровне языка решать собрались?

                                                                                                      А если все либы рассчитаны на си (как вы предлагаетте, всем так делать)
                                                                                                      Нет. Большинство библиотек — вообще не требуют стабильного API. Они поставляются в исходниках и собираются так, как нужно.

                                                                                                      А вот «большие» компоненты, поставляемые отдельно — да, здесь C ABI достаточно.

                                                                                                      P.S. На самом деле самый разумный и, главное, практически отлично работающий подход к стабильному ABI — у разработчиков ядра Linux. Все знают, что внутри ядра — нет никакого стабильного ABI. Но не все осознают насколько, при этом, стабильно ABI на уровне системных вызовов. Windows отдыхает. Но да — это даром не даётся. Это нужно думать, планировать, моделировать, описывать. Делать это для каждой мелкой библиотеки — глупо и ненужно. Но если вы хотите поставлять библиотеку без исходников… то у вас нет выбора.
                                                                                                        0

                                                                                                        Не путайте проблемы API и ABI, я говорил только про ABI. API — да, проблема на стороне разработчика библиотеки.

                                                                                                        0

                                                                                                        #[repr(C)] — это не костыль, а механизм, позволяющий отделить ABI от деталей реализации

                                                                                                          0

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

                                                                                                            0

                                                                                                            Подавляющее большинство либ на Rust (а на текущий момент — так вообще все) линкуются статически, на кой им стабильный ABI?

                                                                                                              0

                                                                                                              Так я про это и говорю: если не нужен ABI, не надо модулей, плагинов, шаринга кода/rdata между независимыми приложениями, удобного интерфейса к JIT и прочего — лучше линковать lto, это эффективнее и сделает каждой функции совой оптимальный ABI.


                                                                                                              Речь же про кейсы когда он нужен, а для системного языка — это маст хев. Для потенциального заменителя C/C++ — тоже.

                                                                                                                0

                                                                                                                Ну так в этих редких кейсах и надо использовать #[repr(C)].

                                                                                                                  0

                                                                                                                  Это не редкие кейсы. Механизм совмещения — фича очень серьезная и используется повсемесно. Пирчем разные модули разрабытывают разные люди/команды/кампании. Связать все это очень важно. Например либу делает одини люди, а используют — другие, вы гарантируете что все либы это сделают, как предлагает khim? Получается я беру либу — проблема, еще беру — еще проблема. И что мне делать? А если все реально начнут делать #[repr(C)] и прочее необходимое, и других вариантов не будет — так проблемы тогда нет, тогда это и будет стабильный ABI для раста.


                                                                                                                  Вот вам еще пример: вот скомпилил я Qt под asan/tasn. Вот они у меня лежат и я их иногда использую. Мне вот очень не понравиться если все минорные обновления компилера начнут его ломать. Или если я не смогу слинковаться с либой из дистриба немного другим компилером, у мнея их вообще 2, clang и gcc, а в репе собиралось одним (причем точно не ими, потмоу что вот они обновились, а все остальное — нет). Понимаете масштаб проблемы?

                                                                                                                    0

                                                                                                                    Как это всё относится к Rust? В Rust вы не будете компилить какой-нибудь qt-rs отдельно от своей программы, а значит и ломаться тут нечему.

                                                                                                                      +1

                                                                                                                      Я вам пытаюсь показать кейс, когда ABI нужен, вы пытаетесь показать кейс где не нужен. Как это к rust относится? Я же конкретно про него пишу — не все либы используют и будут использовать совместимость с си, потому проблема ABI останется. Надо или на си ABI перейти для любой внешней комоновки, или свой стабильный сделать, и это реально очень надо.
                                                                                                                      Просто возьмите кейс где он нужен, а не статическую линковку qt-rs только к совему приложению. Например задейтесь целью зашарить его загрузку между несколькоми независимыми приложениями, контроля над которыми вы не имеете.

                                                                                                                        0

                                                                                                                        То есть у вас есть три сторонних программы, которые статически слинкованы с одной и той же библиотекой, а вы пытаетесь её оттуда выдрать и сделать динамической?


                                                                                                                        Я правильно понимаю ваш кейс?

                                                                                                                          0

                                                                                                                          Не вы, у разработчиков приложений появится такая возможновть, если либа поддержит динамическую линковку. А если динамическия линковка — почти всегда нужен ABI. Вот представьте: обновился в репе компилер — и хоба, прилетает вместе все 40гиг установки, потому что все надо собирать именно с этой версией. Ставите компилер из тестинг репы потому что вам надо? Ваши проблемы. А так, ментейнер возьмет либу, возьмет приложения, скомпилит в пакадж, проверит что все работает. И весь мир в апдейтах прилетать не будет. Вы можете эти приложения локально собрать, подцепив либу из репы, компилер будет другим наверняка, но работать будет и память будет шариться. Это все благодаря ABI и возможности совмещать модули. Все это разношерстная кампания, разные люди, у них разные системы, разные версии и им вот просто очень сильно надо уметь совмещаться внешне без пересборки мира.


                                                                                                                          К стаитческой линковке это тоже относится — иногда оно тоже надо, пример с Qt я выше приводил (забыл упомянуть что статически собирал). В дистрах статические либы тоже присутствуют. С ними точно так же желательно не ломаться как можно дольше.

                                                                                                                            +3
                                                                                                                            А так, ментейнер возьмет либу, возьмет приложения, скомпилит в пакадж, проверит что все работает.
                                                                                                                            Не возьмёт и не проверит. Все попытки продвижения GNU/Linux на десктоп, так или иначе, в это упираются.

                                                                                                                            Да, есть небольшое количество библиотек, которые «следят за гигиеной» и выпускают совместимые версии: libstdc++, Qt, в KDE кой-чего, может ещё пяток можно вспомнить… остальные же на это всё равно забивают.

                                                                                                                            Отсюда — все эти WinSxS, докеры и прочее. Люди всё равно испльзуют программы с «проверенными» библиотеками.

                                                                                                                            Все это разношерстная кампания, разные люди, у них разные системы, разные версии и им вот просто очень сильно надо уметь совмещаться внешне.
                                                                                                                            Не нужно. Разработчики дистрибутивов уже лет двадцать пытаются продвинуть эту «нирванну»… а воз и ныне там: разработчики всё равно пакуют библиотеки с приложением. Посмотрите на какой-нибудь Acrobat Reader: он всё равно тащит с собой ICU и OpenSSL, libORBit и libbonobo, libcurl и libJP2K… потому что это — самый просто способ уменьшить количество головной боли у техподдержки.

                                                                                                                            Да, можно говорить, что это плохо, неправильно и так далее… а толку?
                                                                                                                              0

                                                                                                                              Все верно, я и сам пакую и тащу все статически, для универсальной сборки, которую можно скачать, и запускать неизвестно где. Для винды тоже так делаю, даже с redist не люблю связываться. Вот для flatpak/snap можно указать core вполне, с проблемами пока не сталкивался. А вот в репе — можно и собрать, тянув все динамически. Если говорить именно про ABI — оно просто не соберется иначе, проблему сразу будет видно. И в репах таких приложений тоже хватает.

                                                                                                                                0
                                                                                                                                Если говорить именно про ABI — оно просто не соберется иначе, проблему сразу будет видно.
                                                                                                                                Если мы уже начинаем говорить про «оно просто не соберется» — значит речь уже не про бинарники, значит и стабильный ABI особо уже не нужен…
                                                                                                                                  0

                                                                                                                                  Про бинарник, который попадет в репу и будет тащить все динамически из нее, в репах таких хватает. Просто вы в основном API проблемы описываете, а ABI проблема тут крайне редко возникает (хотя я сталкивался), обычно это бывает если в git выкладывают предкомпиленые либы, вручную собранные.

                                                                                                                    0
                                                                                                                    Ну так в этих редких кейсах и надо использовать #[repr©].
                                                                                                                    вы сами то пробовали так делать? Просто на дистанции в пару десятков лет намного проще победить пару изменений ABI, нежели тянуть сишный интерфейс.
                                                                                                                      0

                                                                                                                      #[repr(C)] — это не обязательно сишный интерфейс, это просто указание не переставлять поля в структуре местами.

                                                                                                                        0
                                                                                                                        Неубедительно. В самом популярной на сегодня OS (а это, как бы, не Windows, а Android) все интерфейсы C-шные. Ни C++, ни COM там нету… и ничего — никто не умер.
                                                                                                  0
                                                                                                  Как это не видели? В винде msvcp*

                                                                                                  msvcp — это не интерфейс ОС, а рантайм С++.


                                                                                                  COM интерфейс это тоже не C

                                                                                                  Но это и не С++. Кстати, кто-нибудь знает, он там патентами какими-то закрыт или как? Удобная же вещь, а за пределами продуктов Microsoft почти никем не поддерживается...

                                                                                                    0

                                                                                                    Да я вкурсе что такое msvcp. Речь про то что он ставится в систему и будет шариться между всеми приложениями, как stdc++ под линем. Чем не интерфейс не на си? Вот WINAPI — да, там везде си, в .net — уже нет, на маке тоже в основном нет. Но это все не к тому, что си интерфейс нажеднее все равно никто не спорит. Это как раз наглядно показывает что это нужная фича, и сишные интерфейсы часто из-за этого выбирают.


                                                                                                    Что COM не С++ я тоже вкурсе, но это и не си, хоть из си и можно работать, из си вообще с чем угодно можно работать.

                                                                                                      0
                                                                                                      Речь про то что он ставится в систему и будет шариться между всеми приложениями, как stdc++ под линем.

                                                                                                      В данном случае, это не достоинство msvcp, а скорее недостаток линя. Или недостаток винды, зависит от точки зрения.


                                                                                                      Так-то и stdc++ можно в теории в нескольких копиях в систему поставить...

                                                                                                        0

                                                                                                        Все так. На винде решают проблему, поставляя redist c приложением и держа несколько копий мажорных версий в системе. На лине — поддерживая какую-то минимальную версию stdc++.
                                                                                                        Так же на лине теперь доступен вариант и как в винде — указывая разные версии core в flatpak/snap, будем попадать на разные версии stdc++. В системе их тоже может стать несколько, и все еще будем их шарить между приложениями.

                                                                                                          0

                                                                                                          Но это обход проблемы стабильного ABI, а не её решение.

                                                                                                            0

                                                                                                            Не совсем, это просто менее стабильный ABI нежели си и один из вариантов решения возникаемой от поломок пробелмы. Но благодаря поддержке его стабильности в определенных пределах — люди впринципе этом могут этим пользоваться, и пользуются. Это впринципе зачем нужен ABI. Если он совсем часто ломается — это так-себе ABI, поддержка усложнится и пользваться станут реже, или станут от чего-то отказываться, это однозначная проблема для кейсов где он нужен. Если же впринципе отказаться от поддержки стабильности ABI — ну так это равноценно тому что его нет, соответственно кейсы где он нужен просто не применимы.

                                                                                                              0
                                                                                                              Если он совсем часто ломается — это так-себе ABI, поддержка усложнится и пользваться станут реже, или станут от чего-то отказываться, это однозначная проблема для кейсов где он нужен.
                                                                                                              В Python ABI подерживается, грубо говоря год (в каждой минорной версии он свой). Много народу уже отказались?
                                                                                                                0

                                                                                                                У питона полно проблем с совместимостью, я постоянно сталкиваюсь, и лучше бы чтобы их небыло. К тому-же притон интерпритируемый язык, но просто перекопилит кэш сам, там куда больше API/библиотек совместимость едет.

                                                                                                                  0
                                                                                                                  Кэш он, может, и перекомпилит — но вот расширения на C — нет. А их, в общем, немало…
                                                                                                                    0

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

                                                                                                          0
                                                                                                          Так-то и stdc++ можно в теории в нескольких копиях в систему поставить...
                                                                                                          Более того — нужно. Если вы старые приложения хотите использовать. А если вы используете библиотеки, собранные gcc 4.x и gcc 5+… получите «массу удовольствия» даже несмотря на одну версию libstdc++…
                                                                                                    –1
                                                                                                    Это то, что всё равно по итогу делается. Я не знаю ни одной «живой» операционки, предоставляющей из коробки C++ интерфейс хоть к чему-нибудь.
                                                                                                    а как же винда, знатная часть интерфейсов которой торчит наружу в виде COM-объектов, имеющих сишный и плюсовый интерфейсы?
                                                                                                      +2
                                                                                                      COM-объекты прекрасно обрабатываются на C, а вот как раз чтобы из C++ с ними можно было работать — там особое расширение, а не стандартный C++
                                                                                              –1
                                                                                              Прикрутите к ней API на C — и поставляйте.
                                                                                              для такой цели c++ подходит лучше раста
                                                                                              Попытки «заморозить» C++ ABI показали, что пользоваться этим всё равно умеют единицы, а проблемы это вызывает у всех.
                                                                                              что вы понимаете под «пользоваться ABI»? И какие «проблемы» у всех это вызывает? Что вы вообще понимаете под «ABI»? Вот например вот здесь:
                                                                                              Тем не менее C++14 ABI и C++17 ABI несовместим, так что с некоторой частотой это всё равно происходит.
                                                                                              вам известно о каких-то breaking changes о которых не известно никому другому?
                                                                                                +3
                                                                                                вам известно о каких-то breaking changes о которых не известно никому другому?
                                                                                                Почему «неизвестно никому другому»? Известно. Ну вот вам простейший пример:
                                                                                                test.h:
                                                                                                struct Foo {
                                                                                                  int value;
                                                                                                };
                                                                                                
                                                                                                struct Bar {
                                                                                                  static constexpr Foo foo{42};
                                                                                                };
                                                                                                
                                                                                                test1.cc:
                                                                                                #include "test.h"
                                                                                                
                                                                                                constexpr Foo Bar::foo;
                                                                                                
                                                                                                const Foo* baz() {
                                                                                                  return &Bar::foo;
                                                                                                }
                                                                                                
                                                                                                test2.cc:
                                                                                                #include "test.h"
                                                                                                
                                                                                                const Foo* qux() {
                                                                                                  return &Bar::foo;
                                                                                                }
                                                                                                
                                                                                                main.cc:
                                                                                                int main() {
                                                                                                }
                                                                                                


                                                                                                В C++14 всё Ok:
                                                                                                $ g++ -c -std=c++14 test1.cc -o test1.o
                                                                                                $ g++ -c -std=c++14 test2.cc -o test2.o
                                                                                                $ g++ main.cc test1.o test2.o
                                                                                                

                                                                                                В C++17 всё Ok:
                                                                                                $ g++ -c -std=c++17 test1.cc -o test1.o
                                                                                                $ g++ -c -std=c++17 test2.cc -o test2.o
                                                                                                $ g++ main.cc test1.o test2.o
                                                                                                

                                                                                                А смешивать — нельзя:
                                                                                                him@khim1:/tmp/1$ g++ -c -std=c++14 test1.cc -o test1.o
                                                                                                khim@khim1:/tmp/1$ g++ -c -std=c++17 test2.cc -o test2.o
                                                                                                khim@khim1:/tmp/1$ g++ main.cc test1.o test2.o
                                                                                                /usr/bin/ld: test2.o:(.rodata._ZN3Bar3fooE[_ZN3Bar3fooE]+0x0): multiple definition of `Bar::foo'; test1.o:(.rodata+0x0): first defined here
                                                                                                collect2: error: ld returned 1 exit status
                                                                                                


                                                                                                Получите, распишитесь.

                                                                                                Поэтому, в частности, у нас переход на C++17 происходил через flag day.

                                                                                                Эта несовместимость — известна, собственно никто её и не скрывает.

                                                                                                что вы понимаете под «пользоваться ABI»?
                                                                                                Ну вот то, про что вы пишите: выпустить либу — а потом новую версию без пересборки бинарника, который этой либой пользуется. Хорошо работает в случае C интерфейса (как зачастую и делают, даже если «внутри» там сплошной C++), отвратительно — в случае с C++.

                                                                                                Да, это возможно… но надёжнее — интерфейс на C.
                                                                                                  –3
                                                                                                  Получите, распишитесь.
                                                                                                  вот только какое отношение проблемы линковки одного бинаря могут иметь к совместимости ABI между разными бинарями?
                                                                                                    0
                                                                                                    А для этих целей есть разнообразные fabi-version (обратите внимание на 12ю и 13е версии). Ну или всякие чудеса типа вот такого.

                                                                                                    Увы, единственный способ не поиметь проблем — это использовать C и «узкие» интерфейсы. Всё остальное — от лукавого.
                                                                                                      +1
                                                                                                      А для этих целей есть разнообразные fabi-version (обратите внимание на 12ю и 13е версии)
                                                                                                      «corrects», «corrects» и еще раз «corrects»…
                                                                                                      По сути, единственная причина почему сишный ABI не меняется в том, что сам язык практически не развивается. А вот в плюсах иногда ABI приходится расширять по мере изменения языка.
                                                                                                      Ну или всякие чудеса типа вот такого.
                                                                                                      с каких пор __int128 является стандартным плюсовым типом, обязанным иметь одинаковую реализацию в разных компиляторах?
                                                                                                        +1
                                                                                                        с каких пор __int128 является стандартным плюсовым типом, обязанным иметь одинаковую реализацию в разных компиляторах?
                                                                                                        С тех пор, как он был добавлен в psABI?

                                                                                                        А вот в плюсах иногда ABI приходится расширять по мере изменения языка.
                                                                                                        А зачем? Мои можно сразу выделить «переносимое подмножество» — а остальное объявить внутренним делом реализации языка.

                                                                                                        Вот вы тут COM вспоминали… Много там появилось за последние 10 лет? А C++ таки прилично поменялся…
                                                                                                          0
                                                                                                          С тех пор, как он был добавлен в psABI?
                                                                                                          1. psABI != стандарт языка с++
                                                                                                          2. __int128 не является обязательным к реализации согласно psABI
                                                                                                          3. psABI почти никак не описывает эту реализацию
                                                                                                          А зачем? Мои можно сразу выделить «переносимое подмножество» — а остальное объявить внутренним делом реализации языка.
                                                                                                          оно и так выделено. extern «C» называется. Но еще раз: решать проблемы бинарной совместимости через си — самый болезненный из возможных вариантов.
                                                                                                          Вот вы тут COM вспоминали… Много там появилось за последние 10 лет? А C++ таки прилично поменялся…
                                                                                                          Ну так благодаря бинарной совместимости COM и не меняется
                                                                                                    +3

                                                                                                    Зачем такие ужасы выдумывать? Достаточно ведь вспомнить, что в C++17 noexcept — часть типа функции (и участвует в мэнглинге), а в C++14 — нет.

                                                                                                      0
                                                                                                      Спасибо за напоминание.

                                                                                                      Ситуация с noexcept в чём-то лучше: можно создать библиотеку, которая работает и с C++14 клиентами и с C++17.

                                                                                                      А вот с этими переменными — засада полная: сделать так, чтобы модули C++14 и C++17 не конфликтовали нельзя вообще. Никак. Во-всяком случае мне решения найти не удалось…
                                                                                                        0
                                                                                                        Достаточно ведь вспомнить, что в C++17 noexcept — часть типа функции (и участвует в мэнглинге), а в C++14 — нет.
                                                                                                        Я тоже так думал, но простейшая проверка опровергает это утверждение.
                                                                                                          0
                                                                                                          Да уж. Век живи, век учись: Functions differing only in their exception specification cannot be overloaded (just like the return type, exception specification is part of function type, but not part of the function signature).

                                                                                                          И такого в C++ много.
                                                                                                            0
                                                                                                            cannot be overloaded
                                                                                                            очевидно логично
                                                                                                            exception specification is part of function type, but not part of the function signature
                                                                                                            а это чтобы предотвратить такой юзкейс.
                                                                                                            И такого в C++ много.
                                                                                                            согласен, в языках без перегрузок не бывает правил, запрещающих перегрузки
                                                                                                            0

                                                                                                            Она просто слишком простейшая. Рассмотрим лучше вот такой код:


                                                                                                            void bar1(void (*)() noexcept(true))
                                                                                                            {
                                                                                                            }
                                                                                                            
                                                                                                            void bar2(void (*)() noexcept(false))
                                                                                                            {
                                                                                                            }

                                                                                                            В C++14 под x86_64 обе функции манглятся как _Z4bar1PFvvE (ну и bar2 соответственно, но это неважно). В C++17 первая функция манглится как _Z4bar1PDoFvvE, вторая — как _Z4bar2PFvvE.


                                                                                                            На всякий.


                                                                                                            И да, gcc и clang единогласно позволяют написать


                                                                                                            void bar1(void (*)() noexcept(true))
                                                                                                            {
                                                                                                            }
                                                                                                            
                                                                                                            void bar1(void (*)() noexcept(false))
                                                                                                            {
                                                                                                            }

                                                                                                            (обратите внимание на одинаковость имени) в C++17-режиме, но не позволяют — в C++14. Не знаю, насколько это соответствует стандарту.

                                                                                        +1

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


                                                                                        Удобно ведь? Чем раст и занимается, по сути.

                                                                                          –1
                                                                                          Ну вот смысл в том, чтобы без этой подсказки код не компилировался

                                                                                          Нет уж, спасибо :) Может быть, мне действительно нужно получить алиасинг в этом месте для того, чтобы получить byte representation некоего объекта. Не надо за меня думать.
                                                                                            +1

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

                                                                                              +3

                                                                                              При обычном программировании ситуация "массив байт — это реально массив байт" встречается куда чаще, чем ситуация "массив байт — это byte representation некоего объекта".

                                                                                                –1
                                                                                                Фиг его знает. Я вот сейчас пробежался по тем проектам что есть на машине за которой я сейчас сижу, char* в аргументах функций есть только в main(). Но это плюсы. В C по идее должно быть более распространено.
                                                                                                  0

                                                                                                  Любая строка (std::string) — это скрытый массив байт. Который заведомо не является byte representation некоего объекта, просто потому что строка владеет этим массивом.


                                                                                                  Мне вот интересно, сколько костылей пришлось вставить авторам стандартной библиотеки, чтобы компилятор знал, что содержимое строки не алиасится с другими объектами? И знает ли вообще компилятор об этом?

                                                                                                    0
                                                                                                    Я думаю, немного:

                                                                                                    godbolt.org/z/XiA6YZ

                                                                                                    :) Приватные поля классов, пусть даже и char* — это вам не аргумент функции, который может придти ХЗ откуда, в том числе из другого модуля.
                                                                                                      0

                                                                                                      У вас UB в коде: указатель никогда не инициализируется, но при этом используется. И к тому же в примере со строкой используются полностью локальные переменные.


                                                                                                      Если это исправить, то поведение string::fill окажется таким же, как и int foo(int& i, char *p).

                                                                                                        0
                                                                                                        Сам по себе неинициализированный указатель тут значения не имеет. Полностью локальные переменные — да, согласен, но этот пример все-таки несколько искусственный.
                                                                                                          +2

                                                                                                          А что насчёт вот такого примера? Он что, тоже искусственный? Вроде бы совершенно стандартная ситуация, когда надо посимвольно обойти переданную по ссылке строку...


                                                                                                          Обратите внимание, что компилятор даже сам указатель "c" вынужден считывать на каждом шаге цикла, потому что не уверен что тот не алиасится с владеющей им же структурой!


                                                                                                          UPD Нашёл пост на Хабре, откуда я узнал об этом эффекте: https://habr.com/ru/company/pvs-studio/blog/475636/

                                                                                                          0
                                                                                                          Вот, кстати, пример с аргументом-ссылкой в string::fill():

                                                                                                          godbolt.org/z/7oPNmw

                                                                                                          Тоже вполне прилично разворачивается. Но да, тут &i тоже не может придти хз откуда. Но такой сценарий все-таки куда более частый, чем ваш.
                                                                                                            +1
                                                                                                            Но такой сценарий все-таки куда более частый, чем ваш.

                                                                                                            Ну, это как бы ваш сценарий, вы же первый придумали переменную i по ссылке передавать для проверки алиасинга...

                                                                                                              0
                                                                                                              Там смысл был в том, что оба аргумента могут придти ХЗ откуда.

                                                                                                              Карма не позволяет писать ответы слишком часто, поэтому отвечу здесь же и на второй ваш комментарий:

                                                                                                              Да, но если эту функцию РЕАЛЬНО ВЫЗВАТЬ, скажем, в main():

                                                                                                              godbolt.org/z/BtFJDr

                                                                                                              то опять же в месте вызова все развернется более-менее прилично, если компилятор знает, откуда что берется.
                                                                                                                0

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

                                                                                                                  0
                                                                                                                  Там смысл был в том, что оба аргумента могут придти ХЗ откуда.

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


                                                                                                                  Карма не позволяет писать ответы слишком часто

                                                                                                                  Подправил этот момент.

                                                                                                                    +1
                                                                                                                    Но ведь приватные данные класса тоже могут ссылаться хз на что, и даже на второй аргумент который мы передаваем.

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

                                                                                                                    Подправил этот момент.

                                                                                                                    Благодарю! :)
                                                                                                  –2
                                                                                                  Ну вот смысл в том, чтобы без этой подсказки код не компилировался, а если вы эту подсказку импользовали чтобы компилятор проверил что вы нигде её не нарушили.
                                                                                                  проблемы начинаются когда я хочу чтобы без этой подсказки код компилировался и работал. Так, как я его написал.
                                                                                                    +1

                                                                                                    Когда одни Умные программисты встречают код написанный другими Умными программистами, обычно они не одну ночь дебажатся, а потом пишут в рабочие чатики "смотрите какую хрень я нашел в нашем проекте".

                                                                                                      –3
                                                                                                      да, код пет проджекта на 100 строчек кажется очень красивым. Не потому, что его не писали «умные программисты», а потому, что его не писал никто кроме вас.

                                                                                                      А вот когда вы лет через 10 заглянете в rust проект, переживший пару сотен «умных программистов», десятки тысяч «срочная фича, дедлайн вчера» и ни одного рефакторинга («всё ж работает!»), но с кучей unsafe костылей (которые неизбежно будут появляться везде, где борроучеккер будет препятствовать изменениям кода), вот тогда вы будете не одну ночь дебажиться, подавляя желание переписать всё с нуля (ибо времени не выделено), и напишете в рабочий чатик «смотрите какую хрень я нашел в нашем проекте». И вам там ответят «да, это надо переписать, там где-то был тикет на это, лет 5 назад, но Вася Пупкин уволился и делать его некому».
                                                                                                        0

                                                                                                        Покажите проект с кучей unsafe-костылей. Или вы скажете что они все маленькие и плохие? Даже в rustc ансейфа очень мало, назвать его маленьким язык не повернется. При том что это блин компилятор, с кучей низкоуровневой магии.


                                                                                                        Если вернуться чуть ближе к миру смертных и посмотреть на типичную библиотеку вроде actix то там 54 ансейфов на 54750 строк кода. Учитывая что почти все ансейфы — однострочные, получаем сколько? 0.1% ансейф кода? Ну да, это явно можно назвать кучей ансейф костылей.


                                                                                                        Возьмем serde_json, 15к строк кода, пять ансейфов
                                                                                                        Возьмем parity-ethereum, 200к строк кода, 68 ансейфов.


                                                                                                        Продолжать?

                                                                                                          –1
                                                                                                          а что, популярные открытые плюсовые библиотеки плохо написаны? Типа буста? Или компиляторы?

                                                                                                          Я говорю про типичный прод типичного бизнеса, который практически не заинтересован в качестве кода. Тот самый плюсовый код, который вы критикуете, обитает преимущественно в них. И таких проектов на расте сейчас раз-два и обчелся, он попросту слишком молод.

                                                                                                          Даже в rustc ансейфа очень мало, назвать его маленьким язык не повернется. При том что это блин компилятор, с кучей низкоуровневой магии.
                                                                                                          куча низкоуровневой магии там в миддленде и бекенде. Тех, которые не на расте.
                                                                                                            +2
                                                                                                            а что, популярные открытые плюсовые библиотеки плохо написаны? Типа буста? Или компиляторы?
                                                                                                            молод.

                                                                                                            Парити — это буст или компилятор?


                                                                                                            куча низкоуровневой магии там в миддленде и бекенде

                                                                                                            Простите, а MIRI тогда это что?
                                                                                                            Задача раста — компилировать в LLVM. С чем он и справляется, будучи написан полностью на расте.


                                                                                                            И таких проектов на расте сейчас раз-два и обчелся, он попросту слишком молод.

                                                                                                            На них хватает проектов, просто вы о них возможно не слышали.


                                                                                                            Решил наш собственный микросервис растовый проверить, 10к строк, два ансейфа.


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

                                                                                                              –2
                                                                                                              Взял вот наш микросервис растовый, 10к строк, два ансейфа.

                                                                                                              возьмите коммерческий растовый проект хотя бы на 10 миллионов строк, тогда и поговорим.
                                                                                                                +2

                                                                                                                Что-то мне этот разговор напоминает


                                                                                                                image


                                                                                                                Ну и даже если — какая разница? 99.99% людей никогда не пишут проекты на миллионы строк кода. Даже если там что-то вдруг пойдет не так (почему? Какой механизм за этим стоит), это затронет жалкую горстку людей. Остальные могут пользоваться бенефитами, которые гарантированно есть на проектах до миллион строк.


                                                                                                                Кстати, насчёт молодого раста — ему сейчас столько же лет, сколько было сишарпу в 2006, когда им уже активно пользовались.

                                                                                                                  0
                                                                                                                  Не, ну честно, одно дело — разработка кучкой энтузиастов, которые болеют за идею, другое — людьми из бодишопов, которые фигак-фигак и в продакшн. Думаете, там кто-то будет стесняться влепить десяток unsafe, если «сроки горят»?
                                                                                                                    +2

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


                                                                                                                    А во-вторых написать сейф вариант часто короче и быстрее написать чем ансейф, посмотрите тот же пример выше с get_unchecked против [], поэтому ленивый разработчик скорее словит панику чем уб.


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

                                                                                                                    –1
                                                                                                                    Что-то мне этот разговор напоминает
                                                                                                                    одумайтесь. Вы сравниваете заведомо плохой код на плюсах с заведомо хорошим кодом на расте и приводите это в аргумент того, какие плюсы плохие. До этого вы сравнивали раст с плюсами приводя в пример вообще сишный код.
                                                                                                                    Остальные могут пользоваться бенефитами, которые гарантированно есть на проектах до миллион строк.
                                                                                                                    да вы бы хоть такой пример привели. Просто любой большой проект, который не энтузиасты в свободное время делают, и не разработчики языка, а обычные программисты из тех самых 99.9%, которые перекладывают json'ы, закрывают тикеты и у которых нет времени рефакторить код на каждую хотелку.
                                                                                                              0
                                                                                                              Зачем далеко ходить? Можно взять сабж Бенчмаркинг гейма и посчитать % ансейфов.

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

                                                                                                              Да и вообще, Расту надо доказывать не производительность кода (тут сомнений мало), а производительность написания.
                                                                                                                0

                                                                                                                Зависит от целей. Написать быстрый код на расте проще, чем на жс или на java. То есть если буквально есть цель написать сервис, который держит миллион рпц и не выжирает 300% памяти сервера, то на расте получится написать проще и быстрее.


                                                                                                                А если вам не нужен быстрый код то и раст не нужен.

                                                                                                              +2

                                                                                                              Для того, чтобы подобного ужаса не случилось, в Rust достаточно одного правила: в основном проекте не должно быть никакого unsafe! Если требуется что-то хитрое — пиши абстрактную библиотеку.


                                                                                                              В С++ аналогичный набор правил намного сложнее.

                                                                                                      0
                                                                                                      ну вот простейший (хотя и довольно-таки патологический) пример… внушает, да
                                                                                                      нет. в случае с make_unique дополнительно выполняется явная инициализация (0 для инт, вызвался бы конструктор для пользовательского типа)
                                                                                                      +1
                                                                                                      Я предпочитаю иметь свою т.зр. в своих программах:
                                                                                                      1. Использую new/delete — ручное управление
                                                                                                      2. Использую unique_ptr — RAII
                                                                                                      3. Выбираю shared/weak_ptr — ARC
                                                                                                      то, что язык поддерживает RAII а библиотеки с его помощью автоматизируют ручное освобождение памяти (и иных ресурсов, btw), никак не отменяет того факта, что управление памятью в с++ ручное.
                                                                                                      4. Подключаю boehm — оппа — программа с GC
                                                                                                      зачем?
                                                                                                        –1
                                                                                                        Похоже, у нас разное понимание автоматического управления памятью. Приведите пжл, ваше определение.
                                                                                                        зачем?
                                                                                                        пример просто для полноты картины
                                                                                                          0
                                                                                                          RAII поддерживается и в Rust (при этом более гибко, чем в C++, позволяя, если необходимо, освободить ресурсы досрочно). То есть в нем ручное управление памятью?
                                                                                                            –1
                                                                                                            РАИИ это да, но потом нужно вручную носиться с этой писаной торссылкой, передавая из рук в руки.
                                                                                                              0
                                                                                                              Заимствование и владение в Rust большенство проблем решает.
                                                                                                                –2
                                                                                                                Ахах, так это и есть эта проблема… Носиться = заимствовать [под роспись и по очереди]
                                                                                                                  0

                                                                                                                  Кроме непонятных эмоциональных аналогий какие-то аргументы будут?

                                                                                                                    –1
                                                                                                                    Никаких эмоций — ОВ это ручное управление циклом жизни переменной под дулом компилятора. Весьма неудобно
                                                                                                                      0
                                                                                                                      под дулом компилятора

                                                                                                                      Снова аргументация от эмоций.

                                                                                                                        +1
                                                                                                                        GC удобнее, но не везде применим.
                                                                                                                        Под дулом компилятора такими вещами заниматься лучще, чем без него. Вооюще пора понять, что в современных развитых языках компилятор друг, а не враг программиста.
                                                                                                                      0
                                                                                                                      Это существенно более гибкий механизм, чем чистая RAII. При этом столь же безопасный.
                                                                                              0
                                                                                              Язык с ручным распределением регистров быстрее, чем язык с автоматическим при прочих равных. Ваш К.О.
                                                                                              +5

                                                                                              Посмотрел первый тест reverse-complement. Прямо с самого начала идут различия.
                                                                                              В Расте:


                                                                                              stdin.lock().read_to_end(&mut data).unwrap();

                                                                                              В С++:


                                                                                              // read line-by-line, according to game rule. Should be replaced by fread()
                                                                                              while (fgets_unlocked(cur_pos, remainbytes, stdin) != 0)

                                                                                              Разве это можно напрямую сравнивать на большом количестве строк? Дальше там еще больше различий идет. Если omp c thread::spawn еще можно сравнить, то в треде там совсем по разному обработка идет.

                                                                                                +1
                                                                                                Растик по ходу сжульничал. В описании задачи особо упомянуто, что «Each program should: read line-by-line a redirected FASTA format file from stdin (grow the data, buffered-read by buffered-read; don't get the size and make a single allocation.) [...]». Интересно, много ли там такого.
                                                                                                  +2
                                                                                                  Обе реализации используют одинаковое количество памяти – 1MB.

                                                                                                  Вы же не думаете, что когда вы читаете в С++ «до конца строки», стандартная библиотека не буферизирует чтение?

                                                                                                  Более того, С++ версия вычисляет общий размер ввода, что формально нарушает правила.

                                                                                                  По поводу этих условий есть определенная дискуссия. Предлагается по меньшей мере переформулировать их для ясности.
                                                                                                    +2
                                                                                                    Я ничего не думаю, я просто вижу, что реализация, в которой все читается одним куском, «немножко» нарушает правила. В реализации на C++ буфер тоже выделяется один раз, это так, но там хотя бы чтение в него происходит line by line в соответствии с правилами.

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

                                                                                                      Из внутренней дискуссии, конкретному по тому вопросу, который вы подняли:
                                                                                                      The description has said «read line-by-line» since Dec 2004, in-spite of the fact that even back then we understood that what seemed to be «read line-by-line» in-say CPython defaults to a buffered read.

                                                                                                      I think «read line-by-line» actually meant don't write a program that will fail when the workload increases 40x.

                                                                                                      Насколько я вижу по реализациям – большинство программ читают таким образом, каким им это удобно.
                                                                                                        0

                                                                                                        Создатель этой игры не смог сформулировать что значит line by line строго поэтому забанил половину решений как ему захотелось. И это только один момент почему этот бенчмарк ниочем.

                                                                                                          +1
                                                                                                          Я согласен с вашим замечанием. Но лучше бенчмарка, для которого сообщество потрудилось бы написать достаточное количество эффективных реализации на разных языках, у нас нет.
                                                                                                            +3
                                                                                                            Написал я под этот бенч решение на nodejs, которое превосходило в два раза текущее. Его выпилил за «нарушение постановки задачи», хотя на любых тестовых данных оно выдавало правильные результаты.
                                                                                                            Данный бенч (или его владелец) очень непоследователен в правилах: половина решений в некоторых тестах использует ассемблерные вставки. Что в итоге мы этим показываем: как крут ассемблер или как крут тестируемый язык?
                                                                                                        0
                                                                                                        Сравнил гошный мандельброт с растовским, показалось, что там мало того, что алгоритмы существенно отличаются, так ещё и входные параметры разные.
                                                                                                    +8
                                                                                                    Этак если посмотреть на реализацую бенчмарков-победителей на разных языках, то можно увидеть, что там соревнуются в основном «кто лучше распараллелил да применил нужные интринсики SSE/AVX/...» (писать на фортране можно на любом языке). В pidigits все используют gmp для арифметики, в reverse-complement rust использует unsafe memchr из libc и т.д. и т.п. Всё это далеко от идиоматического C++ или Rust. Поэтому конкретно эти бенчмарки сравнивают непонятно что с непонятно чем.

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

                                                                                                    В исходниках, кстати, есть идиоматические реализации алгоритмов без хитрых трюков, но так не победить =)
                                                                                                      0

                                                                                                      Ну интринзики можно было бы и в C++ и в Раст добавить, было бы понятно как модифицировать другой пример чтобы сравнять, сравнивались бы уже сами компиляторы. Хотя clang это и C++ и Раст и так =)
                                                                                                      Про преимущества оптимизации у мемори-сейф, ну так в С++ тоже есть всякие restrict и расширения, которые теоретически эту разницу нивелируют.
                                                                                                      Тут же Раст прямо нарушает условия, так что С++ даже нельзя в ответ модифицировать.

                                                                                                        –1
                                                                                                        Формально именно в стандартном C++ restrict нет (по крайней мере пока), это из C99. Но фактически AFAIK тот же g++ в него умеет:

                                                                                                        godbolt.org/z/TGuECo

                                                                                                        В случае с restrict он вычисляет результат в compile time.
                                                                                                          0

                                                                                                          Ну это да, потому и пишу расширений. У gcc есть еще __attribute__ с кучей всего полезного не стандартного. У msvc есть __assume() итд.

                                                                                                          0