Предпочитайте Rust вместо C/C++ для нового кода

Автор оригинала: Cliff L. Biffle
  • Перевод

2019-02-07


  • Когда использовать Rust
  • Когда не использовать Rust
  • Когда использовать C/C++
  • Ложные причины использования C/C++
  • Приложение: моя история с C/C++
  • Приложение: хор

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


TL;DR: C/C++ имеет достаточно конструктивных недостатков и альтернативные инструменты разработки уже находятся в достаточно хорошей форме, поэтому я не рекомендую использовать C/C++ для новых разработок, за исключением особых обстоятельств. В ситуациях, когда вам действительно нужна мощь C/C++, используйте вместо него Rust. В других ситуациях вам все равно не следовало бы использовать C/C++ — используйте что-нибудь другое.


Когда использовать Rust


Такие приложения, как критически важные для безопасности прошивки, ядра операционных систем, криптография, стеки сетевых протоколов и мультимедийные декодеры (в течение последних 30 лет или около этого) в основном были написаны на C и C++. Это именно те области, в которых мы не можем позволить себе быть пронизанными потенциально эксплуатируемыми уязвимостями, такими как переполнения буфера (buffer overflows), некорректные указатели (dangling pointers), гонки (race conditions), целочисленные переполнения (integer overflows) и тому подобное.


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


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


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

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


(Если вам не нужны все эти критерии… тогда, смотрите следующий раздел.)


Я внимательно слежу за Rust с 2013 года и язык значительно повзрослел. По состоянию на конец 2018 года^1^ я думаю, что он достаточно зрелый, чтобы начать рассматривать его как вариант, если ваша организация спокойно относится к генерации не оптимального кода. Я был одним из первых пользователей C++11 в 2011 году, и мой текущий опыт работы с Rust лучше, чем опыт с C++11 GCC в то время. Что о чем-то говорит.


Почему 2018? Потому что теперь можно заниматься разработкой под "голое железо" и для встраиваемых систем (например, модификацией ядра), не полагаясь на нестабильные функции из ночной сборки набора инструментов Rust (nightly Rust toolchain). К тому же изменения в редакции 2018 являются превосходными.


Я поддерживаю свои слова собственными действиями. Вместо того, чтобы просто говорить, я портирую свой высокопроизводительный встроенный и графический демонстрационный код с C++ на Rust. Это код для режима реального времени, в котором важны отдельные циклы ЦПУ, где у нас нет достаточного количества оперативной памяти для выполнения текущей задачи и мы нагружаем оборудование до предела. Версия кода на Rust более надежна, часто быстрее и всегда короче.


Когда не использовать Rust


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


Конкретный пример: если бы меня попросили написать вычислитель символьной алгебры (symbolic algebra evaluator), или параллельную постоянную структуру данных (concurrent persistent data structure) или что-нибудь еще, что выполняет тяжелые манипуляции с графами, то я, вероятно, обращусь к чему-то что имеет трассирующий сборщик мусора — например, что-то другое, но не Rust. Но это не будет C++, где мне пришлось бы работать так же усердно, как в Rust, но с меньшими затратами. Я бы лично подтолкнул вас к Swift^2^, но Go, Typescript, Python и даже Kotlin/Java — вполне разумный выбор.


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


Когда использовать C/C++


Вот несколько веских причин, по которым вы все равно можете выбрать C/C++:


  • Вы уверены, что ваш код никогда не подвергнется атакам, не подвержен атакам повреждения данных или на него кто-то полагается. Типа, взлом прототипа на Arduino. Тогда вперед.


  • У вас есть нормативные или договорные требования для использования определенного языка. Хотя в этом случае вы, вероятно, выберете Ada, которая в первую очередь значительно менее подвержена ошибкам, чем C.


  • Ваша целевая платформа не поддерживается в Rust. Поскольку Rust поддерживает почти все, что связано с бэкэндом LLVM, включая множество платформ, которые не поддерживаются в GCC. Это довольно короткий список, но в настоящее время он включает, не поддерживаемые 68HC11 и 68000. (Rust поддерживается на MSP430, Cortex-M и т.д., поддержка AVR в процессе стабилизации). И если вы на телефоне, десктопе или сервере, который вы сами поддерживаете. Даже на мейнфрейме IBM System 390.


  • Вы ожидаете, что ваш компилятор/набор инструментов (toolchain) будет сопровождаться соглашением о коммерческой поддержке. Я не знаю, чтобы кто-нибудь предлагал такое для набора инструментов Rust. Я также не знаю, чтобы кто-нибудь предлагал его сейчас для GCC, когда был куплен CodeSourcery.


  • Вы ожидаете, что ваша система станет достаточно большой, чтобы производительность rustc стала для вас проблемой и вы ожидаете, что это произойдет быстрее, чем rustc смогут улучшить. Rustc компилирует медленнее, чем GCC. Команда внимательно следит за этим, и ситуация улучшается. Ваш опыт будет во многом зависеть от сложности вашего кода C++; один из моих проектов собирается в Rust быстрее, чем в GCC.


  • У вас есть большая кодовая база C++, которая экспортирует только C++ интерфейс, не является независимым от языка API (например, интерфейс extern "C", каналы (pipes) или RPC). Семантика C++ настолько сложна, что ни один язык не справится с ней должным образом. (Swift, возможно, подходит ближе всего.) Наличие подобной системы у вас в какой-то момент вас "укусит".



Ложные причины использовать C/C++


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


У C/C++ есть 30+ лет работы над компилятором, поэтому они будут быстрее/надежнее.


В основном я слышу это от людей, которые не работали над компиляторами. Это заблуждение.


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


Rust использует те же бэкэнд компилятора, оптимизаторы и генераторы кода, что и Swift и C++ (Clang). В большинстве случаев код работает так же быстро или быстрее, как сегодня скомпилированный C/C++.


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


… у меня для вас плохие новости. Ваши C/C++ программисты, вероятно, не так хорошо обучены, как вы думаете. Я работаю в месте, где все имеют очень твердое мнение о C++, которое они не хотят менять, работаю вместе с одними из лучших программистов на планете. И тем не менее, при проверке кода я все еще регулярно ловлю их на допущенных ошибках или коде полагающимся на неопределенное поведение (UB). Ошибки, которые они не допустили бы в Rust.


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


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


Для C программистов, смысл в том, что они пытаются сделать сначала назойливый двусвязный список, который бывает невозможно выразить в безопасном Rust (но мы над этим работаем). Это достаточно распространенная жалоба, поэтому существует целый учебник, относящийся к ней, Learning Rust With Allly Too Many Linked Lists.


Его также очень сложно сделать правильно в C/C++ и я могу практически гарантировать, что вы написали такой один, но он просто не корректен для многопоточной / SMP среды. Вот почему его также трудно выразить в Rust.


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


Приложение: моя история с C/C++


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


Я использую Cи примерно с 1993 года, а C++ с 2002 года, оба более или менее постоянно. Я использовал их в разных окружениях, включая продакшн в Google, Qt, Chrome, графические демонстрационки, ядра ОС и встроенные микросхемы управления батареями. При создании микропрограммной компании Loon, я твердо выступал за C++ (версии С99); мы быстро перешли на C++11 (в 2011 году), и черт возьми, это окупилось. Позже я вложил много энергии в то, чтобы убедить другие команды в X использовать C++, а не Cи для их прошивок.


Когда Loon не смог найти работающий на "голом железе" C++ код crt0.o для тогда еще новых процессоров Cortex-M, я написал его; они все еще работают на нем. Я написал замену стандартной библиотеки C++, которая устраняет выделение памяти в куче и добавляет некоторые Rust-о подобные возможности. Я знаю стандарт C++ не обычно хорошо… или, по крайней мере, я его изучил. Я "заржавел" в прошлом году или года два назад (каламбур).


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


Приложение: хор


Хор в который я собираю примеры умных людей согласных со мной. :-)


Крис Палмер (Chris Palmer): State of Software Security 2019: (выделено мной)


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

Эссе Алекса Гейнора (Alex Gaynor) The Internet Has a Huge C/C++ Problem and Developers Don't Want to Deal With It (в Vice, во всех местах):


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

(У него также есть отличные статьи в блоге по этой теме.)


Manish Goregaokar из Mozilla, пишет в ycombinator что fuzzing тестирование частей Rust кода в Firefox не выявило ошибок безопасности, но помогло найти ошибки в C++ коде, который он заменил:


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

Это было более или менее нашим опытом с fuzzing кода Rust в firefox, ух… Фаззинг обнаружил множество паник (и отладочных ассертов / ассертов о «безопасном» переполнении). В одном из случаев он действительно обнаружил ошибку, которая не была замечена в аналогичном коде Gecko около десяти лет.

Copyright 2011-2019 Cliff L. Biffle — Contact

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

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

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

    +15

    10 надмозгов из 10, опять нейросети тестируете на чейтателях?

    +6
    я твердо выступал за C++ (версии С99)

    Шта? В оригинале «I advocated hard for C++ (over C99)». Вы пропаганду-то хоть переводите правильно :) Наброшу на вентилятор — тут одна контора на букву M уже предпочла раст, и теперь у нее проблемы, а команду растаманов пришлось разогнать :)
      +10

      Вообще по этому поводу нет беспокойства. Rust уже остановить невозможно. Тем более, что Mozilla никогда особо и не вкладывалась в Rust. Теперь же быстрее сформируют Rust Foundation, язык уже довно созрел для самостоятельной взрослой жизни.

        0

        Вы очень точно уловили суть спасибо.

          0

          Спасибо, хотелось бы больше деталей. Поделитесь ссылкой?

            +6
            тут одна контора на букву M уже предпочла эффективных менеджеров программистам и менеджера-сову на пост CEO (успешно выгнав инженера), и теперь у нее проблемы, и инженеров пришлось разогнать :)

            У вас слишком много фактических ошибок в предложении. Починил, не благодарите.

              0

              Ммм, вот оно как, оказывается. А то, что на момент начала пиления серво доля FF и Chromium на браузерном рынке была примерно одинаковой, а на момент забрасывания его пиления (сколько там сейчас в него коммитов в неделю, один?) доля Chromium больше примерно на порядок — это просто совпадение? Или тоже свалите все на менеджера-сову? А с моей точки зрения это больше похоже на то, что "инженеры" вместо того, чтобы пилить фичи и оптимизации и стараться держать FF on par с Chromium, просрали годы усилий на игру в RIIR. А то, что произошло с мозиллой теперь — закономерный итог всего этого. Браузер с долей на рынке в единицы процентов (и продолжающей уменьшаться) все менее и менее интересен с точки зрения поисковиков (того же гугла), платежи от которых составляют львиную долю бюджета Мозиллы. "Инженеры" сами вырыли себе яму.

                +2
                Или тоже свалите все на менеджера-сову?

                Да, сова все это время бросала еще больше ресурсов компании на написание еще одного "нужного" расширения в стандартной поставке, вместо наращивания этой самой доли. Только в последние годы начали немного наверстывать упущенное PR-компанией об упоре на приватность.


                и стараться держать FF on par с Chromium

                И что же было не on par с Chromium? rust и компоненты мозиллы на нем — показатель того, что технологически firefox оказался даже впереди хромого. Который, неизбежно, тоже начинает работу над компонентами на rust в своей кодовой базе.

                  –3

                  Приведу пример из своего личного опыта. Я раньше пользовался на десктопе и на андроид-мобилке браузером Brave (на движке Chromium), но некоторое время назад разрабы там поломали синхронизацию, и я решил попробовать перелезть на мозиллу. Скажу прямо — когда Brave починил синхронизацию, я был просто счастлив перелезть обратно. На десктопе ещё туда-сюда, но на мобилке Мозилла — это тормозное, жрущее батарейку говно. И, судя по свободнопадающей который год рыночной доле мозиллы, так думаю не я один. На фоне этого заявления адептов, что "мозилла впереди хромого потому, что раст" просто смешны. Раст не дал мозилле никаких явных преимуществ, не помог отвоевать долю рынка, это просто-напросто смертельно дорого обошедшиеся шашечки.

                    –4
                    На десктопе ещё туда-сюда, но на мобилке Мозилла — это тормозное

                    Эх, помню времена, когда 99% жалоб на тормоза были из-за отсутствия плавной прокрутки из коробки.


                    Но вы не поверите, ужасная поддержка Android — очередной менеджерский продолб. Там не только в этом проблемы и проблемы "тормозит и жрет батарейку" не от ущербности движка. Вместо того, чтобы сфокусироваться на технической части, они решили сфокусироваться на клепании 10 разных версий с разными интерфейсами, в том числе на движке хромиума.

                      0
                      «На движке хромиума» — это вы про версию для iOS, для которой собственные движки запрещены?
                        0

                        Да, но они и для Android это сделали.

                          0
                          Это про какой продукт речь?
                            0

                            Firefox Focus/Klar. Справедливости ради, они таки перешли на gecko.

                          0
                          для которой собственные движки запрещены

                          Оо… Я знал что у аппл всё плохо со свободой выбора, но вот это прям откровение.

                        +6

                        Где цифры? Все это ваше субъективное восприятие реальности. Я так тоже могу сказать, ибо перелез на FF под Android не из-за любви к Mozilla, а потому что он мне оказался удобнее. И никаких тормозов и проблем с батареей, при том что иметь десятки и сотни открытых вкладок для меня норма.

                          +6
                          плюсую.
                          На десктопе сижу на ФФ с времён ещё допотопной версии 2.0. Андроидного фокса поставил сразу же, как он вышел. Всегда прекрасно работает и там, и там.
                      +10
                      Другой конторе на букву M ничего не помешало слить свой браузер и без всякого Rust. ИМХО, не в языке тут дело.
                        +3
                        Ммм, вот оно как, оказывается. А то, что на момент начала пиления серво доля FF и Chromium на браузерном рынке была примерно одинаковой, а на момент забрасывания его пиления (сколько там сейчас в него коммитов в неделю, один?) доля Chromium больше примерно на порядок — это просто совпадение?

                        Не вижу закономерности imageДоля chrome стремительно росла до появления на свет servo, а доля firefox снижалась. В 2013 году (когда mozilla объявила, что работает над новым браузерным движком) доля chrome уже была в 2 раза больше доли firefox.
                        команду растаманов пришлось разогнать
                        Только одних растаманов?
                          –3
                          Доля chrome стремительно росла до появления на свет servo, а доля firefox снижалась.

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

                            +5

                            А может дело в маркетинге и в том, что самая главная страница интернета настойчиво рекомендовала перейти на Chrome? Посмотрите на динамику популярности IE, по сравнению с ним FF еще хорошо держится.

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

                      Теперь весь интернет заспамлен раст-пропагандой, и они могут говорить «ну не шмогли, не повезло, но как пытались!» :))
                      +7

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


                      Borrow checker не такой уж и страшный: когда к нему привыкаешь, уже и замечать перестаешь. При разработке прикладного ПО редко когда действительно приходится решать проблемы, связанные с размещением в памяти. Большую часть времени ощущение от разработки такое же, как и на языке с GC.

                        –6
                        Отличная статья. Я не хочу писать двусвязный список на Си, не смог на с++ а сейчас почитайте книжку почему его нельзя сделать на безопасном расте.
                        Я нашел много ошибок с выделением памяти у коллег на с++, но не могу найти их у себя. Поэтому перешёл на раст. Прямо каминг оут какой-то. Блин с такой пропагандой раста ему врагов не надо, достаточно друзей.
                          –3
                          PS «стабильная» версия раста выходит примерно раз в месяц. Как хорошо, что они ушли из с++ и его комитета. Может и наконец оставят с++ в покое. Программистов на расте примерно в десять раз меньше, чем на с++. Но в интернете в обсуждениях они активнее, агрессивнее и вроде как их даже больше.Интересно — почему. Какие будут версии? :)
                          Ждём святой инквизиции. Веруешь ли ты в непогрешимость святого Раста и не исповедуешь ли ты богомерзкого с плюс плюса или еретического Си. Покайся пока не поздно…
                            +6
                            Программистов на расте примерно в десять раз меньше, чем на с++.
                            Любой популярный язык, в том числе и сам C++, когда-то проходил стадию «программистов на X примерно в десять раз меньше, чем на Y».
                              +5

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

                                –1

                                Действительно странно, что системщики не хотят снова становиться джунами только потому, что в Mozilla решили, что будет прикольно урезать зарплатные ожидания путём внедрения очередной якобы серебрянной пули

                                  +3

                                  Лично я только выиграл в зарплате при переходе на раст. А разве где-то это иначе работает? При появлении новой технологии специалисты автоматически не возникают из воздуха — надо или искать энтузиастов или переучивать. И с какой стати соглашаться на меньшие деньги? Тем более, что прошлый опыт будет совсем не бесполезным.

                                    +1
                                    только потому

                                    Не знаю ни одного человека, который перешел на Rust именно по этой причине. Тут вы правы.

                                      0

                                      Так ровно по этой причине надо бойкотировать новые стандарты C++. И люди бойкотируют, впрочем.

                                      –2
                                      А где вы нашли негатив в сторону языка раст? Язык как язык. А вот на страницах дискуссий о языках растоманы безусловно побеждают. Количеством. Активностью. Агрессией. Проблемы у программистов не в языке программирования, а совсем в других местах. Вы победили в дискуссии. Теперь найдите себе работу наконец и займитесь делом.
                                      Самое забавное, что приходят школьники в программирование и носятся с очередой серебряной пулей. История их ничему не учит, потому что оно ее и не знают. В Японии в свое время потратили миллиарды на пролог. Он был объявлен панацеей от всех проблем программирования и языком пятого поколения. И где он теперь. Причем язык то неплохой, но со своими тараканами.
                                        +4

                                        Вот честно, где вы видите агрессию от людей, защищающих Rust? Вот хотя бы в данных комментариях, перечитайте. Вся агрессия идет как раз от противников Раста.

                                          –6
                                          У раста нет противников, но вы упорно их ищете. Где угодно. Теперь скиньте белые одежды проповедника истины в последней инстанции и посмотрите в зеркало. Может противник раста прячется там?
                                            –4
                                            Впрочем лично для меня значимость языка программирования находится где-то на уровне цвета клавиатуры
                                            напомнило
                                            Кроме того, наши летописи за шесть тысяч лун не упоминают ни о каких других странах, кроме двух великих империй — Лилипутии и Блефуску. Итак, эти две могущественные державы ведут между собой ожесточеннейшую войну в продолжение тридцати шести лун. Поводом к войне послужили следующие обстоятельства. Всеми разделяется убеждение, что варёные яйца при употреблении их в пищу испокон веков разбивались с тупого конца; но дед нынешнего императора, будучи ребёнком, порезал себе палец за завтраком, разбивая яйцо означенным древним способом. Тогда император, отец ребёнка, обнародовал указ, предписывающий всем его подданным под страхом строгого наказания разбивать яйца с острого конца. Этот закон до такой степени озлобил население, что, по словам наших летописей, был причиной шести восстаний, во время которых один император потерял жизнь, а другой — корону.

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

                                            — Дж. Свифт. Путешествия Гулливера

                                            Время идет, а люди не меняются.
                                              +2

                                              Наверное это потому, что вы не программируете. Тогда вообще не понятно, что вы делаете в данном обсуждении. Зашли поругаться?

                                                –2
                                                Почему же. Программирую потихоньку лет так 35-40. И за деньги и бесплатно. Только язык программирования — вторичен. Зависит от задачи, истории разработки, и тд. Безусловно есть предпочтения, но они не всегда важны. Посмотрите к примеру первую мою статью здесь, там есть линк на гитхаб. Могли бы и сами догадаться, прежде чем писать чепуху. У меня основное занятие — реконструкция изображений с томографов. Там есть и матлаб и питон и glsl и куда и Фортран и плюсы и ембед всякий. И много много математики.
                                                  +2

                                                  Извините, но мне сложно представить себе программиста, для которого возможности языка, тот инструментарий и те гарантии, которые он дает — по значимости где-то на уровне цвета клавиатуры (хотя может быть для вас цвет имеет большое значение?).


                                                  Но раз так, тогда я вам рекомендую везде использовать Rust. Вам же все равно, а так вы поможете распространению языка )

                                                    –2
                                                    Не прокатит. Для продукта нужна стабильная версия компилятора.Не пройдет FDA. Проблемы индейцев (программистов) шерифа не волнуют.
                                                    Там покрытие тестами такое плотное, и дизайн проходит столько ревью, что с аллокациями проблем просто не может быть, нужно по коду доказать, что такого не может быть. Это медицинское оборудование. Может лет через десять. Ну и советы Ваши в данном случае просто забавны. Я там двадцать лет работаю. Мой код работает примерно на половине всех CT сканеров в мире (GE)
                                                    хотя может быть для вас цвет имеет большое значение

                                                    Любой кроме красного :)
                                                      +1

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

                                                        0
                                                        Так формально и доказывается. С графом состояний.
                                                          0

                                                          А тесты тогда зачем?


                                                          И какими инструментами доказываете, если не секрет?

                                                            –2
                                                            Тесты на качество картинок. На скорость. Ну и память заодно тоже.
                                                            Я очень мало могу рассказать. Только в очень общих чертах. Есть NDA. И любая информация только через специальных пресс атташе. Лучше я Вам не про программы, а про программистов:
                                                            Нам на работе понадобился фантом в форме человека (Для отладки томографа) заполненный водой и с тонкой кожей. Я предложил купить куклу в сексшопе и налить в нее воды.
                                                            Зависло на этапе оформления. «Кукла из сексшопа на нужды группы программистов, для отладки программы». Не прошло :(. Купили фантом за >10K

                                                            Могу ссылку на статью для примера о реконструкции, я там в соавторах, поскольку эту реконструкцию и писал
                                                            pubmed.ncbi.nlm.nih.gov/16467583
                                                              +1
                                                              Есть NDA.

                                                              Не представляю, каким должно быть NDA, чтобы запретить вам сказать «Coq»/«Frama-C»/etc, если инструменты известные и сделаны не вашей компанией. А в приватность инструментов не верю по ряду причин.

                                                                +1
                                                                Допустим компания Х использует для реконструкции верилог, а компания Y glsl, а компания Z cuda, а компания Т opencl. Что Вы можете сказать о компаниях?
                                                                  +1

                                                                  Вообще ничего. Кроме того, что реконструкция имеет малое отношение к формальной верификации.

                                                                    –2
                                                                    Вообще ничего

                                                                    Ну а я очень много…
                                                                    Кроме того, что реконструкция имеет малое отношение к формальной верификации

                                                                    Ваше мнение, в данном конкретном случае, безусловно очень важно для меня.
                                                                      +1
                                                                      Ну а я очень много…

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


                                                                      Ваше мнение, в данном конкретном случае, безусловно очень важно для меня.

                                                                      Моё мнение тут совершенно ни при чём, это просто вещи разных типов. Это, ну, как диалог вроде
                                                                      — А какие языки вы используете для решения этой задачи?
                                                                      — Одна компания использует git, а другая — svn, что вам это скажет?

                                                                        –4
                                                                        Насчёт первого. Железо, операционную систему и ещё много деталей.
                                                                        Много. Например, что те кто испольует GIT они скорее мультисайт, то есть у них несколько мест разработки и скорее всего автоматическая сборка и линукс. Svn — они работают под виндовс.а графика директ-икс
                                                                          0
                                                                          Например, что те кто испольует GIT они скорее мультисайт, то есть у них несколько мест разработки и скорее всего автоматическая сборка и линукс.

                                                                          А язык, язык-то какой?


                                                                          А что такое мультисайт, я не знаю.

                                                                            –2
                                                                            Это из clearcase пришло. Когда у вас несколько стораджей для одного репозитория. И они между собой синхронизируются. Насколько я знаю SVN так не умеет. Впрочем я не уверен, лично я им не пользовался
                                                                            0
                                                                            Мой вариант: Те кто использует гит, скорее всего работают на МакОс, пишут на Свифт.
                                                                            А те кто на СВН: работают на ДОС, графики нет, используют Basic.
                                                                            Почему нет?
                                                                              –3
                                                                              Я говорю об вполне определенной области, реконструкции изображений томографа.
                                                                              Так что вряд ли Бейсик или Свифт с мак ос
                                                                0
                                                                А тесты тогда зачем?

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

                                                                  –1

                                                                  Отрицанием (или снятием двойного отрицания) же можно привести одно к другому.

                                                                    +1

                                                                    Неа, не получится. Формально доказывая что продукт работает вы рискуете ошибиться дважды (в продукте и при формализации ТЗ, а если это АПК — то ошибка возможна ещё и при построении модели аппаратной части).


                                                                    Ну а отсутствие нежелательного поведения обычными тестами не ловится в принципе.

                                                                      0
                                                                      Формально доказывая что продукт работает вы рискуете ошибиться дважды (в продукте и при формализации ТЗ, а если это АПК — то ошибка возможна ещё и при построении модели аппаратной части).

                                                                      А кто мне мешает ошибиться в тесте? Тесты же не даны нам свыше, они тоже как-то следуют из ровно той же формализации ТЗ.

                                                                        0

                                                                        Объём кода мешает. Меньше кода — меньше ошибок, просто из-за статистики.


                                                                        Тут идеальны вовсе ручные тесты, поскольку они вообще не требуют формализации ТЗ или построения модели аппаратной части.

                                                                          0

                                                                          Ну это да.


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

                                                                            –2
                                                                            Не стоит гадать.я действительно не могу рассказывать. Программа на уровне дизайна построена для удобста верификации и состоит из унифицированных модулей Я за это специальный приз получил с бонусом.
                                                                            Вот про восстановление изображений в vi3dim и использованный там код я могу рассказать, что угодно в пределах разумного, как ее CTO, а GE или THALES нет, не могу.
                                                                              0

                                                                              Эх, аж жаль, что так и не узнать мне про ещё один кейс формальной верификации в дикой природе.

                                                                                –1
                                                                                Ну она не совсем дикая. Там водятся всякие SixSigma. Эти задачи не всегда легко формализуются. Часто можно доказать соответствие программы некой формальной спецификации, но это не является доказательством корректности программы, а только соответствия этой формальной спецификации
                                              +1

                                              Ещё раз — негатив не в адрес раста, а в адрес совершенно убогой и назойливой пропаганды типа этой статьи. Почему это пропаганда? Вот типичный пример:


                                              И тем не менее, при проверке кода я все еще регулярно ловлю их на допущенных ошибках или коде полагающимся на неопределенное поведение (UB). Ошибки, которые они не допустили бы в Rust.

                                              Таки допустили бы. "Интереснее всего в этом вранье то, что оно — вранье от первого до последнего слова." ©


                                              P.S. Работайте тоньше, меньше безаппеляционного тона и вранья, очевидного любому человеку с бэкграундом, и сами не заметите, как весь "эмоциональный негатив" куда-то исчезнет.

                                                +4

                                                Конечно, в unsafe-коде вы всегда сможете допустить UB. Но речь же в статье именно о тех местах, где разработчики C++ допускают по невнимательности UB, тогда как в Rust этого бы не произошло. Автор говорит, что ловит коллег на ошибках, которые они не допустили бы в Rust — очевидно, что это про те места, которые покрывает безопасный Rust.


                                                Но даже если говорить про unsafe, когда компилятор вас заставляет его писать — невозможно не обратить на это внимание, не остановиться и не подумать, а чего, собственно, тут небезопасного — это тоже хорошо предостерегает от ошибок по невнимательности.

                                                  –2
                                                  Тут именно UB, допущенный по невнимательности, что там, что там. Ошибка при расчете выравнивания — это мина замедленного действия, на x86 она может не замечаться годами. То, что такая ошибка происходит в unsafe блоке — слабое утешение. Пропагандисты, утверждая, что «в раст такой ошибки допустить было бы нельзя», как правило (намеренно?) забывают приложить к этому утверждению сносочку "*в safe подмножестве языка", в результате (намеренно?) создают ложное впечатление. Впрочем, при обсуждении аналогичной статьи (кстати, что характерно, опубликованной здесь тем же человеком, что опубликовал и данную статью тоже) на эту тему уже хорошо сказал другой человек, не хочу повторяться.
                                                    +2
                                                    То, что такая ошибка происходит в unsafe блоке — слабое утешение.

                                                    Это не утешение, это — принципиальный момент, о котором я уже сказал в комментарии выше.

                                                      +3
                                                      как правило (намеренно?) забывают приложить к этому утверждению сносочку "*в safe подмножестве языка", в результате (намеренно?) создают ложное впечатление

                                                      Вам везде мерещатся заговоры. Автор говорит о том, что в тех местах, где его коллеги допускали UB, используя Rust они бы UB не допустили. Очевидно, что речь идет о safe Rust, потому что в unsafe допустить UB можно. Вы занимаетесь каким-то буквоедством и выискиваете в тексе то, чего там нет: где сказано, что используя Rust в принципе невозможно получить UB? Зачем вы додумываете за автора то, чего он не говорит? Проблема C++ именно в том, что в нем легко можно получить UB на ровном месте, по невнимательности, не ожидая вообще, что тут может быть UB. С Rust такое уже не прокатит.

                                                        –1

                                                        Вот только как пример автора, так и мой относятся к областям, где требуется прямая манипуляция адресами и паддингом (аллокаторы, санитайзинг адресов в сисколлах, и так далее) — грубо говоря, где требуется работать с адресами как с целочисленными значениями. Safe rust в принципе не позволяет такого.

                                                          +1

                                                          О каком примере автора речь? Если вы про тот баг из NaCl — то Rust его бы поймал: попытка вычислить 1 << 32 в отладочной сборке приводит к панике. Независимо от того, safe там или unsafe.

                                                            0

                                                            В одном случае к некорректному выравниванию указателя потенциально приводит некорректный сдвиг, в другом — арифметическая ошибка. Причины разные, результат одинаковый — потенциальное обращение по невыравненному указателю. В обоих случаях могли бы помочь тесты, но их не было. Но в целом да, насколько я вижу в playground, попытка сдвигать u32 на константу 32 сразу приводит к ошибке компиляции, если сдвигать не на константу, то все зависит от того, происходит ли сдвиг в отладочной сборке или в релизной.

                                                              +2

                                                              Арифметику без зав. типов не проверить, чудес не бывает.

                                                    –3
                                                    I still regularly catch them making bounds errors or relying on undefined behavior. Errors they wouldn't make in Rust.

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

                                                    Ого… поругайтесь на автора, он около 10 лет работал в Гугле (из 25-27 лет в ИТ), не знает о чем говорит, но вы похоже знаете лучше него. :))) (было бы полезно посмотреть на ваш «послужной список»)

                                                    www.youtube.com/user/cbiffle/videos
                                                    www.linkedin.com/in/cbiffle
                                                    github.com/cbiffle
                                                      0
                                                        –3

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

                                                          +1
                                                          Я просмотрел весь тред с первого сообщения и не увидел в нём апелляций к авторитетам, кроме того комментария, на который я ответил.
                                                            –1

                                                            Да, в явном виде этого действительно не было. Однако лично я читаю "защищает от UB" как "защищает от большинства UB" или даже как "защищает от появления UB на пустом месте". Такое утверждение единичным примером с UB в кастомном аллокаторе (как будто я каждый день пишу аллокаторы!) не опровергается, в рассуждениях явно не хватает дополнительного аргумента о типичности либо необходимости подобного кода для программ на Rust.


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

                                                              0
                                                              Для опровержения заявлений типа «такую-то ошибку в языке N невозможно допустить» достаточно одного-единственного примера такой ошибки, и найти такой пример (сюрприз-сюрприз) не составило большого труда. Никакой апелляции к авторитетам для этого не требуется. Или вы считаете «апелляцией к авторитетам» простую констатацию факта, что человек с бэкграундом, который знает, куда смотреть, способен легко найти такой пример? Я не согласен с таким толкованием :)
                                                              А ведь это далеко не очевидно, я вот со своим бэкграундом даже не могу представить чтобы я сделал в каком-нибудь проекте свой аллокатор, но не покрыл его тестами, в том числе проверяющими выравнивание...

                                                              Я тоже. Но вот автор obstack почему-то этого не сделал…
                                                                –1
                                                                Я тоже. Но вот автор obstack почему-то этого не сделал…

                                                                Ну и фиг с ним, мне важнее качество моего кода.

                                                                –1
                                                                лично я читаю «защищает от UB» как «защищает от большинства UB» или даже как «защищает от появления UB на пустом месте»
                                                                Стоп, а к чему вообще Rust тогда? Ведь есть C++, который защищает от UB.
                                                                  +2

                                                                  Вот как раз в С++ всякие UB способны появляться на пустом месте. Недавно ещё один способ получить UB появился — передать что-нибудь по ссылке в сопрограмму. И это после инвалидации указателей, использования после перемещения, thread::detach и подобных функций...

                                                                    0
                                                                    А в Расте нельзя сделать тоже самое в unsafe-блоке? Да, знаю, нужно использовать обычные safe-секции — ну так и в C++ в таких случаях можно multithreaded shared_ptr использовать, вполне себе защита.
                                                                      +4

                                                                      Можно. Только в C++ у вас вся программа в unsafe, а в расте вы можете сфокусироваться на явно выделенных кусках кода, а в остальном вас компилятор подстрахует.

                                                                        +5

                                                                        Ещё бы кто сам shared_ptr защитил:


                                                                        std::shared_ptr<foo> empty;
                                                                        empty->bar = 42; // UB
                                                                        
                                                                        std::shared_ptr<foo> not_empty = ...;
                                                                        baz(std::move(not_empty));
                                                                        not_empty->bar = 42; // потенциальное UB

                                                                        И нет, "всё тоже самое" в unsafe блоке в Rust провернуть нельзя. Потому что unsafe не выключает никаких проверок у стандартных примитивов-контейнеров.


                                                                        Да, я могу обратиться к чужой памяти если буду действовать через указатель. Но пока я работаю с вектором через итератор — я не получу UB, даже в unsafe блоке. Rust просто не даст сделать активный итератор невалидным.

                                                                          0
                                                                          ну так и в C++ в таких случаях можно multithreaded shared_ptr

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

                                                    +3
                                                    Перевод от Бота
                                                    +5
                                                    Ох уж эти назойливые списки, постоянно меня от работы отвлекают.
                                                      +6
                                                      Предпочитайте Rust
                                                      Предпочитайте не использовать повелительное наклонение в дословных переводах. Звучит ужасно.
                                                        –4

                                                        Самый главный вопрос не раскрыт: поддерживает ли Rust BLM?

                                                            –2
                                                            И если уж искать замену Си в _системном_ программировании, то на мой взгляд, это Nim, а не Rust.

                                                            dev.to/aachh/nim-v-rust-4kh5
                                                              0
                                                              Но на язык без скобочек будут нормально смотреть лишь любители Питона.

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

                                                                Скобочки или отступы это последнее, на что нужно смотреть при выборе языка, на мой взгляд. Для их ярых любителей, однако, подойдёт V, но он на ещё более ранней стадии развития.

                                                                  –1

                                                                  V — это скам.

                                                                    0
                                                                    Почему?
                                                                  +1
                                                                  Но на язык без скобочек будут нормально смотреть лишь любители Питона.

                                                                  Хаскелистам тоже норм, там даже круглых скобочек куда меньше, чем в питоне.

                                                                +2
                                                                Yes, Rust is more safe. I don’t really care.

                                                                После этих слов статью можно закрыть.

                                                                +3
                                                                Апелляция к авторитету хорошо работает для детей лет до 7-8. Потом чем дальше, тем хуже. Однако почему-то большинство статей «почему ты должен немедленно бросить этот мерзкий языческий С++ и перейти на сторону света ржавчины» пишутся именно в виде апелляции к авторитету какого-то хрена-с-горы. Я вполне готов допустить, что оный пэрсонаж может быть даже действительно в чём-то говорит дело. Но меня это всё равно не убеждает, а покровительски-панибратский тон вызывает лишь раздражение, саркастическую усмешку и вопрос, так ли уж автор хорошо разбирается в вопросе, если не понимает таких простых вещей в жизни?

                                                                Кстати в тему же этого вопроса: пример про написание связных списков, мягко говоря, удивил. В 99,99% случаев никто в здравом уме и трезвой памяти не станет решать типовые и давно решенные задачи, когда уже есть множество готовых проверенных решений в виде STL, Boost, Poco и да-тысячи-их-на-любую-потребность. И если это хоть на 1% не так в предлагаемой альтернативе — её просто ещё рано толкать в прод и масс.маркет. А если так, зачем такой пример?

                                                                — Вот что реально было бы интересно узнать (ну, т.е. как «реально»… было бы совсем реально — уже давно бы сам узнал, но пока просто интересно в рамках расширения кругозора) — это с какими полезными и удобными возможностями С++ придётся неминуемо расстаться при переходе на раст. There's no free lunch, сколько это стоит? И почему выбрали такое идиотское название — «ржавчина».
                                                                  +2

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

                                                                    +1
                                                                    Я ничего не понял в вашем ответе. Как некая идентичная функциональность, присутствующая в обоих альтернативах, может быть аргументом за или против? Она есть и там и там. И?
                                                                      +6

                                                                      Объясняю: стандартный аргумент растохейтеров — "посмотрите, в Расте даже двусвязный список я не могу без извращений сделать". Возможно, это как-то связано с тем, что двусвязные списки любят спрашивать на собеседованиях, и вообще они превратились в эдакий "Hello, world!" в области структур данных.


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

                                                                        0
                                                                        Даже нормально передать аргумент в функцию не могу. Это лучше?
                                                                          0

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


                                                                          Кстати, а что не так с передачей аргумента в функцию?

                                                                            –1
                                                                            Да все не так. Нельзя было даже просто взять и напечатать отладку, как написано здесь в учебнике, вызов функции требовал заимствование.
                                                                            doc.rust-lang.org/1.8.0/book/references-and-borrowing.html
                                                                            Here’s the code:

                                                                            let mut x = 5;
                                                                            let y = &mut x;

                                                                            *y += 1;

                                                                            println!("{}", x);
                                                                            This code gives us this error:
                                                                            Но теперь, уже можно. Я хренею, еще не успел язык выучить, как он уже поменялся и офиц.учебник устарел. :fail:
                                                                              0

                                                                              Вот так опять нельзя. Borrowchecker стал лучше и поэтому ваш пример компилируется т.к. фактического нарушения у вас нет (время жизни переменной y заканчивается сразу после *y += 1;) https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=c58504a8417accd7a57d65355ec6f23e

                                                                                –2
                                                                                Это прекрасно. Но работает при комментировании любого из println

                                                                                А какие спецэффекты можно получить на программе посложнее 5 строк…
                                                                                  +2

                                                                                  "спецэффекты" — это то, что может произойти в рантайме. А тут всё отловил компилятор.

                                                                                +2

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


                                                                                К слову, вызов функции и сейчас требует заимствования. Просто на момент вызова printf переменная y уже пропала, а потому использовать переменную x снова можно.


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

                                                                                  +1
                                                                                  вы что, специально сохранили ссылку на старую версию чтобы было на что ныть?
                                                                                  Нет, когда у меня не получилось просто воспроизвести, я только что нагуглил: G «rust borrow variable», 1я же ссылка.

                                                                                  Собственно, предлагаю вернуться к упомянутым «извращениям».

                                                                                  P.S. printf как сила привычки =)
                                                                                    –2

                                                                                    Есть автоматическое управление памятью, а есть ручное с разной степенью валидации. Третьего не дано. Берите то что без извращений.

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

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

                                                                                      И я не могу никак понять, почему передача параметра по значению, требует заимствования.
                                                                                      И это при наличии в языке шести, Карл, комбинаций передачи параметра: x, &x, mut x, &mut x, &mut &x, mut &x!
                                                                                        +2

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


                                                                                        И это при наличии в языке шести, Карл, комбинаций передачи параметра

                                                                                        Из перечисленных вами конструкций только три являются способами передачи параметра: x (по значению), &x (по разделяемой ссылке), &mut x (по эксклюзивной ссылке). Ведущий mut никак на передачу параметра не влияет.


                                                                                        Кстати, у всех этих конструкций есть прямые аналоги в языке Си.

                                                                                          0

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

                                                                                            0

                                                                                            А где вы видите функцию? println! — это макрос, который заимствует переданные параметры.

                                                                                      0
                                                                                      В вашем примере (но не любом другом) можно печатать и так:
                                                                                      let mut x = 5;
                                                                                      let y = &mut x;
                                                                                      *y += 1;
                                                                                      println!("{}", &y);
                                                                                      println!("{}", &x);
                                                                                        –2
                                                                                        Да ладно, а вот так уже нельзя
                                                                                            let mut x = 5;
                                                                                            let y = &mut x;
                                                                                            
                                                                                            *y += 1;
                                                                                            
                                                                                            println!("{}", &x);
                                                                                            println!("{}", &y);    
                                                                                        

                                                                                        Почувствуйте разницу!

                                                                                        И такими дикими дизайнерскими решениями Раст наполнен прилично. Нарушается принцип наименьшего удивления.
                                                                                        Например, я вчера автоматически написал такой неверный код
                                                                                        fn foo(a: i32) -> i32
                                                                                        {
                                                                                            a;
                                                                                        }
                                                                                        

                                                                                          0

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


                                                                                          Всё-таки &mut — это прежде всего инструмент для передачи параметров.


                                                                                          Кстати, а что с вашей функцией foo-то не так?

                                                                                            +2

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

                                                                                              –2
                                                                                              Можно поставить запятую ради интереса, тогда компилятор сам предложит точку с запятой =)

                                                                                              Я так в каком то другом случае по совету компилятора тасовал всякие варианты mut и ссылок, пока круг не замкнулся.
                                                                                                0

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

                                                                                                  +2

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

                                                                                              0

                                                                                              В таком коде в одном потоке проблем быть не должно. Прикол в том что &T разрешено шарить между потоками, отсюда и более строгие правила.

                                                                                                +3

                                                                                                Товарищ Siemargl, ваше рвение в изучении Rust похвально, но может, вы всё-таки прочитаете по нему учебник?

                                                                                                  +1
                                                                                                  Так мало того, что прочитал, так даже дал выше ссылку на него.
                                                                                                  doc.rust-lang.org/1.8.0/book/references-and-borrowing.html

                                                                                                  И выясняется, что тут не читаем — «тут рыбу заворачивали» =)

                                                                                                  Кстати, ни из ссылки 1.8.0 (а Раст то 1.46), ни из титула не видно, что это устаревшая документация.
                                                                                                    0
                                                                                                    • Вас удивляют правила заимствования в языке, вокруг которых он фактически и выстроен;
                                                                                                    • Вы не можете отличить вызов функции от вызова макроса;
                                                                                                    • Вы не понимаете как работает println! и испытываете трудности с расстановкой mut.

                                                                                                    А вы точно книгу-то читали? Или это из разряда "смотрю в книгу — вижу фигу" у вас?

                                                                                                      0
                                                                                                      Если заменить вызов println на вызов функции в этом примере, ничего не меняется, правила ОВ не дадут это сделать.

                                                                                                      И да, я затрудняюсь писать на Раст, идиотский синтаксис и ограничения мне мешают.
                                                                                                        +2

                                                                                                        Ну если наличие в программе GC или UB (на выбор) вам не мешает, то, наверное, и нет особой надобности использовать именно Rust. Синтаксис тут вряд ли играет какую-то существенную роль.


                                                                                                        Я в свое время перешел на Rust потому, что мне понадобился статически типизированный язык без GC и с хорошей системой управления зависимостями. Синтаксис поначалу не нравился, но потом перестал испытывать с ним какие-либо неудобства. И так было со многими моими знакомыми: синтаксис нормальный, просто сначала он может быть непривычен.

                                                                                                      –1

                                                                                                      А как вам вариант искать документацию по Rust на, внезапно, официальном сайте Rust, а не искать в гугле?

                                                                                                        0
                                                                                                        Моя ссылка, внезапно, тоже на официальный сайт Раста.
                                                                                                          0

                                                                                                          Вот только на самом сайте проще найти ссылку на последнюю версию TRPL.

                                                                                                    +2

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


                                                                                                    Например, я вчера автоматически написал такой неверный код

                                                                                                    И что страшного произошло? Компилятор вам сказал:


                                                                                                    error[E0308]: mismatched types
                                                                                                     --> src/main.rs:1:19
                                                                                                      |
                                                                                                    1 | fn foo(a: i32) -> i32 {
                                                                                                      |    ---            ^^^ expected `i32`, found `()`
                                                                                                      |    |
                                                                                                      |    implicitly returns `()` as its body has no tail or `return` expression
                                                                                                    2 |     a;
                                                                                                      |      - help: consider removing this semicolon

                                                                                                    Так сложно прочитать сообщение об ошибке и убрать ;? Вот честное слово, детский сад какой-то.

                                                                                                      –2
                                                                                                      Да не очень то сложно, просто по привычке поставил.

                                                                                                      Но, кстати, а чем точка с запятой то помешала?

                                                                                                      А вот здесь, например, лишняя запятая почему то не помешала, где логика???
                                                                                                          let arr:[i32;4] = [10,20,30,40,];
                                                                                                        +1
                                                                                                        Да не очень то сложно, просто по привычке поставил.

                                                                                                        То есть опять язык не выучили вы, а виноват Rust.


                                                                                                        Но, кстати, а чем точка с запятой то помешала?

                                                                                                        Точка с запятой после выражения отбрасывает его значение и возвращает (). И это написано в TRPL.


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

                                                                                                        А это для того, чтобы можно было писать вот так:


                                                                                                        let strings = [
                                                                                                            "there might be many difficult tasks",
                                                                                                            "on the path of one who only started to learn programming",
                                                                                                            "but reading through documentation",
                                                                                                            "is certainly not one of them",
                                                                                                        ];

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

                                                                                                          +1

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


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


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

                                                                                                            –2
                                                                                                            Т.е недостаточно того, что у функции явно описан возвращаемый тип, пустой?

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

                                                                                                            В общем мне надоело. По теме же — Стоит предпочесть что угодно вместо С, только не Раст.
                                                                                                              0

                                                                                                              Ну, в Си или С++ вы тоже можете написать void foo() { return 42; } и это, если я правильно помню, тоже будет ошибкой. В Rust всё так же, только без return

                                                                                                                –2
                                                                                                                Вообще то нет, неправильно помнишь.
                                                                                                                в С и С++ валидно
                                                                                                                void foo() { 42; }

                                                                                                                в С валидно и
                                                                                                                void foo() { return 42; }
                                                                                                                и просто
                                                                                                                foo() { return 42; }
                                                                                                                — варнинг
                                                                                                                  –1

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

                                                                                                                +1

                                                                                                                В Rust нет "процедур", то есть функций, которые не возвращают значения. Когда такая нужна — пишется функция, которая возвращает значение типа "пусто". Но пустое значение при этом она-таки должна вернуть! Вот пример:


                                                                                                                fn foo() {
                                                                                                                }

                                                                                                                Это то же самое, что


                                                                                                                fn foo() -> () {
                                                                                                                    ()
                                                                                                                }

                                                                                                                Или


                                                                                                                fn foo() -> () {
                                                                                                                    return ();
                                                                                                                }

                                                                                                                Или


                                                                                                                fn foo() -> () {
                                                                                                                    ;
                                                                                                                }

                                                                                                                Так что вы можете написать:


                                                                                                                fn foo() {
                                                                                                                    statementA;
                                                                                                                    statementB;
                                                                                                                }

                                                                                                                Что на самом деле будет означать:


                                                                                                                fn foo() -> () {
                                                                                                                    statementA;
                                                                                                                    statementB;
                                                                                                                    ()
                                                                                                                }
                                                                                                          –3
                                                                                                          Ну наконец то я сформулировал, то что ощущал.

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

                                                                                                          Собственно, это и приводит меня в когнитивный диссонанс.
                                                                                                          Я считаю это бредом, идиотизмом, и что такого не должно быть ни в одном ЯП.
                                                                                                          (Хотя и понимаю, что это просто потому, что разработчики Раста хотели помочь, но недопомогли ввиду тупого ОБ-чекера, который понимает только один из двух вариантов)
                                                                                                            0

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

                                                                                                              0
                                                                                                              Спасибо, но мне тут ниже уже посоветовали обратное =)
                                                                                                              Если вы пытаетесь заставить программу работать, случайным образом тасуя синтаксические элементы, то я не удивлён, что у вас проблемы с изучением Rust.

                                                                                                                +5

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

                                                                                            –4
                                                                                            Пытаешься внятно и спокойно объяснить, почему такие статьи никого ни в чём не убеждают и что нужно исправить, чтобы убеждали, а в ответ получаешь тучу минусов в комент и карму от тихушников и ни одного ответа по существу.
                                                                                            раст == детский сад?
                                                                                              –2
                                                                                              раст == детский сад?
                                                                                              И почему выбрали такое идиотское название — «ржавчина».

                                                                                              Да-да, "внятно и спокойно".


                                                                                              P.S. Не минусовал.

                                                                                                0

                                                                                                С каких пор три минуса — это туча? (А в карму так не больше двух могло прилететь, но мне кажется что и вовсе всего один был)

                                                                                                +6

                                                                                                Про двусвязнай список — это отсылка к частому упреку в сторону Rust, что, дескать, на языке с GC можно запросто список соорудить, на C/C++ — тоже — просто возьми указатели, а на Rust не так-то просто: нужно думать о слабых умных указателях, дабы избежать циклических ссылок. Ну либо также, как в C/C++, но с unsafe — и где тогда ваша хваленая безопасность в Rust?


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


                                                                                                При переходе с C++ придется расстаться с ООП (в виде наследования), со всякой нетипизируемой шаблонной магией, с самоссылающимися структурами данных да и вообще с алиасингом указателей на изменяемый объект, также придется привыкать программировать без исключений и UB :)


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

                                                                                                  0
                                                                                                  примитивный двусвязный список на указателях — это совсем не безопасная вещь
                                                                                                  Это каким таким образом?
                                                                                                    +2

                                                                                                    Можно где-нибудь "потерять" ссылку на освобождённой элемент. Вроде бы банальная проблема из серии "не делайте так", в смысле "не оставляйте ссылки на элементы где попало" — вот только оставлять их придётся, иначе не видать удаления за O(1).


                                                                                                    Можно случайно добавить элемент в два списка сразу. Можно освободить список не очистив его. Можно освободить элемент списка не удалив его их списка...

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

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

                                                                                                          +2

                                                                                                          Ну здрасьте! Все перечисленные мною ошибки легче всего допустить как раз в Си. Плюсы ограждают от части из них, Rust — от ещё большей части

                                                                                                            +1
                                                                                                            Нет, я к тому, что этот функционал, который порождает сложности реализации, может быть вообще не нужен. Вот допустим у меня в программе есть только один список объектов заданного типа — зачем мне защита от добавления сразу в два? И в C++ я могу об этом не думать. А в Rust придется платить сложностью реализации за ситуации, которые никогда не возникнут.
                                                                                                              +2

                                                                                                              Проблема в том, что когда у вас появится второй список, то вы гарантированно забудете обновить некоторые из мест, где предполагалось, что список единственен. Или когда у вас появится многопоточность, вы где-нибудь забудете добавить лок, либо локи будут настолько coarse-grained, что лучше бы многопоточности не было.


                                                                                                              А ещё вы можете ошибиться и не подумать о том, о чём надо подумать (тогда как тайпчекер заставит вас о чём-то думать), или подумать неправильно. Сорян, что я тут со своими формальными доказательствами, но у меня вот практически на прошлой неделе был случай, когда я думал, что ручкой и бумажкой на листочке всё доказал, а при переносе доказательства в машину termination checker обнаружил (и я потом перепроверил и убедился, что это не false positive), что кое-где у меня доказательство одной из кучи взаимно индуктивных лемм строится на цепочке вида «A верно, потому что B верно, которое верно потому, что C верно, которое верно, потому что A». Ну, то есть, ерунда, переделывать надо.


                                                                                                              Вот и с растом так же, пусть и для нормального кода.

                                                                                                                +2
                                                                                                                Да, да, когда появится второй список, когда будет многопоточность, когда будет 1000000 объектов и т. д., и т. п. А на деле это происходит в 1% случаев.
                                                                                                                  +2

                                                                                                                  Что вы такое пишете, что требования изменяются и развиваются всего в 1% случаев?

                                                                                                                    –2
                                                                                                                    А что у Вас за требования, что исконный синглтон вдруг должен перестать им быть? И с чего это вдруг однопоточному приложению вдруг понадобился многопоток (а если понадобился, почему оно изначально не многопоточное)? Возможно, конечно, мне не хватает опыта, но ИМХО такие перекройки происходят нечасто, а когда происходят — это грандиозное событие, и ни одна деталь не остается без внимания.
                                                                                                                      +4
                                                                                                                      А что у Вас за требования, что исконный синглтон вдруг должен перестать им быть?

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


                                                                                                                      Или, например, система для кластеризации новостей держала некий глобальный контекст, считающий некоторое расстояние между документами с весами, соответствующими ранее виденным документам (можете думать о TF-IDF в качестве модели). А потом внезапно оказалось, что неплохо бы поддерживать несколько разных предметных областей и временных интервалов кластеризации.


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


                                                                                                                      И с чего это вдруг однопоточному приложению вдруг понадобился многопоток (а если понадобился, почему оно изначально не многопоточное)?

                                                                                                                      Приложение-то многопоточное, алгоритм однопоточный. И могло, например, внезапно выясниться (ну там, после профилирования на реальных данных), что некие места имеет смысл распараллелить. Опять же, из практики, чтоб далеко не ходить, с тем же спеллчекером оказалось, что кое-какие этапы его работы имеет смысл распараллелить, потому что спеллчекер работал дольше, чем ожидалось, а запросов к сервису было меньше, чем ожидалось (вы.не.гугл.жпг, и поэтому однопоточная обработка каждого запроса с параллелизмом на уровне разных запросов обеспечивала, конечно, тот же максимальный throughput, но существенно большую латентность). Правда, распараллелить не получилось — я к тому моменту посрался с лидом проекта, и он заворачивал любые мои пуллреквесты, и конкретно этот реквест он завернул, что иронично, с обоснованиием «распараллеливание слишком небезопасно, у нас нет гарантий, что это не принесёт баги».


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


                                                                                                                      Или, например, оказалось, что в 2018-м году IO стало достаточно быстрым для того, чтобы некоторые вещи из хранилища запрашивать параллельно, и параллелизация слоя загрузки данных оказалась целым проектом (потому что была написана в предположении, что параллелить её не придётся никогда).


                                                                                                                      Возможно, конечно, мне не хватает опыта, но ИМХО такие перекройки происходят нечасто, а когда происходят — это…

                                                                                                                      …we need to move fast, спринт две недели, стейкхолдеры стейкхолдерят.


                                                                                                                      это грандиозное событие

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


                                                                                                                      и ни одна деталь не остается без внимания.

                                                                                                                      В районе 1910-х годов придумали типы, в районе второй половины XX века придумали алгоритмически эффективные тайпчекеры. Непонятно, почему я, гордый гомо сапиенс, должен служить машине и натягивать свой рыбий (по сравнению с машиной, по крайней мере) attention span на задачи, на которые он заведомо не натянется, если машина может это сделать за меня.


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

                                                                                                                0

                                                                                                                В один список тоже можно добавить элемент два раза, и это будет такой же ошибкой как и добавление в два разных списка.

                                                                                                                  +1

                                                                                                                  Отчасти вы правы. Поэтому я для себя сформулировал такое правило: "Rust упрощает сложное, но усложняет простое". Если вы пишите скрипт в пару строк — Rust для этой цели будет не лучшим выбором. А вот если ваше ПО достаточно сложное или предполагается его усложнение в будущем — то тут издержки Раста со временем окупятся сполна.

                                                                                                                    0

                                                                                                                    В точку. Играться на расте в олимпиадное программирование вообще не вариант.

                                                                                                                      –1

                                                                                                                      А вот не факт, кстати. Я игрался в олимпиадное программирование на плюсах, и мы поймали на финале ACM ICPC столько "ошибок компилятора" (которые лет через пять оказались нашими ошибками), что лучше бы я писал на Расте. Результат бы, наверное, всё же не улучшился — но вот нервов бы мы потратили определённо меньше.

                                                                                                                      0
                                                                                                                      Ну, я бы не сказал, что Rust упрощает сложное — большая часть этих ошибок скорее требует концентрации и дисциплины. А с действительно сложными вещами (например, такими как lock-free программирование) Rust, насколько я знаю, пока не справляется. Хотя вот это была бы настоящая серебренная пуля…
                                                                                                                        0
                                                                                                                        большая часть этих ошибок скорее требует концентрации и дисциплины
                                                                                                                        Что по-другому означает: давайте мы все включая джунов внезапно станем крутыми гуру-профессионалами.
                                                                                                                      +1
                                                                                                                      А в Rust придется платить сложностью реализации за ситуации, которые никогда не возникнут.

                                                                                                                      Но платить никто не заставляет. Лишь указывают на наличие проблем.

                                                                                                                  0
                                                                                                                  Но ведь все те же самые доводы применимы к тезису «односвязный список вещь небезопасная».
                                                                                                                  Но ведь односвязный список, если я правильно понимаю, в Rust реализуется.

                                                                                                                  И тогда получается странное:
                                                                                                                  двусвязный список реализовать нельзя, потому, что он опасен, тем что проблемы№1,2,3…
                                                                                                                  в односвязном списке те же проблемы №1,2,3… но его реализовать можно.
                                                                                                                    +1

                                                                                                                    Эти доводы — против простого списка на Си. И да, против односвязного списка они тоже работают.


                                                                                                                    Двусвязный список на safe Rust реализовать нельзя не из-за этих доводов, а потому что там указатели никак не связаны с отношением владения.

                                                                                                                      0
                                                                                                                      Следует ли вас понимать так, что описанных вами проблем в Rust на односвязном списке возникнуть не может (разумеется если не использовать unsafe и ф-ии его экспортирующие)?

                                                                                                                      ПС
                                                                                                                      А что позволит Rust «запретить» утечку памяти, связанную с забыванием удаления элемента при самописаном листе и сигнатуре:
                                                                                                                      fn extract_from_list(list: tlist, key: int8) -> &mut tlist

                                                                                                                      //извините не знаю Rust, но смысл в том, что удаляемый элемент будем возвращать из ф-ии по ссылке и тогда автоудаления при выходе из scoupe не произойдёт.

                                                                                                                        +1

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


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

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

                                                                                                                          0
                                                                                                                          fn extract_from_list(list: tlist, key: int8) -> &mut tlist

                                                                                                                          Такое в Rust не прокатит, так как тут list перемещен в функцию, а не передан по ссылке, а это значит, что компилятор потребует явно указать лайфтайм для ссылки в возвращаемом значении:


                                                                                                                          fn extract_from_list<'a>(list: tlist, key: int8) -> &'a mut tlist

                                                                                                                          Но чему будет равно время жизни 'a? Значение list явно будет жить меньше, чем 'a, так как оно пропадает при завершении работы функции. Поэтому в таком случае компилятор выдаст ошибку о невозможности вернуть ссылку на объект, которым владеет функция.

                                                                                                                            0
                                                                                                                            Понял спасибо. Т.е. &mut это не владение.

                                                                                                                            Выглядит так, что Rust не какая-нибудь «заумная фигня», а язык, решающий те же актуальные вопросы, что и С++ за zero-cost (разумеется несколько по-другому, это же не D / C++++, а другой язык).
                                                                                                                            С одной стороны интересно, с другой стороны размер rust book говорит, что на rust надо будет десятки часов потратить…

                                                                                                                            Подскажите ещё момент: а в Rust для трэйтов есть имплементации-функций по умолчанию (как в Haskell для тайпклассов)?
                                                                                                                            –2
                                                                                                                            тут list перемещен в функцию, а не передан по ссылке
                                                                                                                            и потому эта функция не имеет смысла.
                                                                                                                            Должно быть
                                                                                                                            type Tlist = Vec<i32>;
                                                                                                                            fn extract_from_list(list: &Tlist, key: usize) -> Tlist {
                                                                                                                                let mut nl = Tlist::new();
                                                                                                                                nl.push(list[key]);  // may panic!
                                                                                                                                nl
                                                                                                                            }
                                                                                                                            
                                                                                                                  0
                                                                                                                  > со всякой нетипизируемой шаблонной магией

                                                                                                                  Ммм, погодите-ка. Шаблонная магия в некотором смысле вся «нетипизируемая», если так можно выразиться, до момента передачи типа в шаблон, после чего всё становится строго типизированным. Шаблон должен отвечать используемому интерфейсу, — да, иначе не соберётся. Т.е повторюсь, все шаблоны как бы одновременно «нетипизируемые», но результат всё равно строго типизирован. По сути, шаблоны это такие «макросы на стероидах» (с).
                                                                                                                  Т.е. я правильно понял, в расте вообще нет шаблонов?
                                                                                                                    +1

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

                                                                                                                      0
                                                                                                                      Я не знаю, как это работает в расте (и, соответственно, что конкретно имеется в виду), но судя по всему, при желании, и в плюсах же тоже можно проверять аргументы шаблонов компилятором на соответствие любым требованиям типа (ну, может не 100% эквивалентно расту, ибо см. выше про отсутствие моих знаний в нём, но для надёжной работы — достаточно). Если хотим «типизировать» параметр шаблона, то требуем, чтобы его тип он наследовался от специального базового класса (::std::is_base_of<> проверяем через ::std::enable_if<> или static_assert()). В этом спец.базовом классе (aka статический интерфейс) просто задаём/перечисляем, но не декларируем (т.е. не пишем реализаций), нужные функции, описывающие абстракный тип. Соответственно, любой наследный класс от этого статического интерфейса будет обязан переопределить эти функции, иначе будет ошибка линковки из-за отсутствия определений. А не наследный класс не пролезет в проверку ::std::is_base_of<>.

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

                                                                                                                      Вполне допускаю, что это лишь некий эрзац-заменитель того, что может раст, ибо имея желание, можно отыскать дырки, однако для практического использования этого достаточно, чтобы избежать случайно-неслучайной подстановки неверного типа.
                                                                                                                        –4
                                                                                                                        узбагойся, расту до С++/D шаблонов как до луны

                                                                                                                        там еще и язык макросов отдельный, чтобы медом не казалось
                                                                                                                          +4
                                                                                                                          Я не знаю, как это работает в расте (и, соответственно, что конкретно имеется в виду), но судя по всему, при желании, и в плюсах же тоже можно проверять аргументы шаблонов компилятором на соответствие любым требованиям типа (ну, может не 100% эквивалентно расту, ибо см. выше про отсутствие моих знаний в нём, но для надёжной работы — достаточно). Если хотим «типизировать» параметр шаблона, то требуем, чтобы его тип он наследовался от специального базового класса (::std::is_base_of<> проверяем через ::std::enable_if<> или static_assert()).

                                                                                                                          Но это всё равно будет проверяться компилятором после инстанциирования.


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

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


                                                                                                                          Представим себе, что мы хотим написать функцию, выбирающую максимум из трёх элементов:


                                                                                                                          template<typename T>
                                                                                                                          T max3(T a, T b, T c)
                                                                                                                          {
                                                                                                                            if (b > a)
                                                                                                                              return b < c ? ...;
                                                                                                                            ...
                                                                                                                          }

                                                                                                                          Скомпилируется ли эта функция? Да. Скомпилируется ли она для интов? Да. Скомпилируется ли для вашего типа, у которого есть только operator<? Нет. Ударит ли вас компилятор по рукам, если вы концептами, SFINAE или ещё как потребуете только operator< или operator>? Нет.


                                                                                                                          А вот в расте или в хаскеле или в языках с нормальным параметрическим полиморфизмом ударит.

                                                                                                                            0