Как стать автором
Обновить

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

Могу ссылку на статью для примера о реконструкции, я там в соавторах, поскольку эту реконструкцию и писал
pubmed.ncbi.nlm.nih.gov/16467583
НЛО прилетело и опубликовало эту надпись здесь
Допустим компания Х использует для реконструкции верилог, а компания Y glsl, а компания Z cuda, а компания Т opencl. Что Вы можете сказать о компаниях?
НЛО прилетело и опубликовало эту надпись здесь
Вообще ничего

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

Ваше мнение, в данном конкретном случае, безусловно очень важно для меня.
НЛО прилетело и опубликовало эту надпись здесь
Насчёт первого. Железо, операционную систему и ещё много деталей.
Много. Например, что те кто испольует GIT они скорее мультисайт, то есть у них несколько мест разработки и скорее всего автоматическая сборка и линукс. Svn — они работают под виндовс.а графика директ-икс
НЛО прилетело и опубликовало эту надпись здесь
Это из clearcase пришло. Когда у вас несколько стораджей для одного репозитория. И они между собой синхронизируются. Насколько я знаю SVN так не умеет. Впрочем я не уверен, лично я им не пользовался
Мой вариант: Те кто использует гит, скорее всего работают на МакОс, пишут на Свифт.
А те кто на СВН: работают на ДОС, графики нет, используют Basic.
Почему нет?
Я говорю об вполне определенной области, реконструкции изображений томографа.
Так что вряд ли Бейсик или Свифт с мак ос
А тесты тогда зачем?

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

НЛО прилетело и опубликовало эту надпись здесь

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


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

НЛО прилетело и опубликовало эту надпись здесь

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


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

НЛО прилетело и опубликовало эту надпись здесь
Не стоит гадать.я действительно не могу рассказывать. Программа на уровне дизайна построена для удобста верификации и состоит из унифицированных модулей Я за это специальный приз получил с бонусом.
Вот про восстановление изображений в vi3dim и использованный там код я могу рассказать, что угодно в пределах разумного, как ее CTO, а GE или THALES нет, не могу.
НЛО прилетело и опубликовало эту надпись здесь
Ну она не совсем дикая. Там водятся всякие SixSigma. Эти задачи не всегда легко формализуются. Часто можно доказать соответствие программы некой формальной спецификации, но это не является доказательством корректности программы, а только соответствия этой формальной спецификации

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


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

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


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

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


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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

Ещё бы кто сам 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 просто не даст сделать активный итератор невалидным.

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

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

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

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

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

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

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

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

V — это скам.

Почему?
НЛО прилетело и опубликовало эту надпись здесь
Yes, Rust is more safe. I don’t really care.

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

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

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

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

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

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

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


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

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

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


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

Да все не так. Нельзя было даже просто взять и напечатать отладку, как написано здесь в учебнике, вызов функции требовал заимствование.
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:

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

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

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

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

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


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


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

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

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

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

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

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

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

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

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


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

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


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

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

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

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

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

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

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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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


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

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


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

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

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

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

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

То есть опять язык не выучили вы, а виноват 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",
];

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

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


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


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

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

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

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

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

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

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

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

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


fn foo() {
}

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


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

Или


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

Или


fn foo() -> () {
    ;
}

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


fn foo() {
    statementA;
    statementB;
}

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


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

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

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

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

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

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

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

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


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

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

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


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


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


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

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

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


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

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

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

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

Нет, я к тому, что этот функционал, который порождает сложности реализации, может быть вообще не нужен. Вот допустим у меня в программе есть только один список объектов заданного типа — зачем мне защита от добавления сразу в два? И в C++ я могу об этом не думать. А в Rust придется платить сложностью реализации за ситуации, которые никогда не возникнут.
НЛО прилетело и опубликовало эту надпись здесь
Да, да, когда появится второй список, когда будет многопоточность, когда будет 1000000 объектов и т. д., и т. п. А на деле это происходит в 1% случаев.
НЛО прилетело и опубликовало эту надпись здесь
А что у Вас за требования, что исконный синглтон вдруг должен перестать им быть? И с чего это вдруг однопоточному приложению вдруг понадобился многопоток (а если понадобился, почему оно изначально не многопоточное)? Возможно, конечно, мне не хватает опыта, но ИМХО такие перекройки происходят нечасто, а когда происходят — это грандиозное событие, и ни одна деталь не остается без внимания.
НЛО прилетело и опубликовало эту надпись здесь

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

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

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

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

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

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

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

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

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


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

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

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

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

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


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

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

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, так как оно пропадает при завершении работы функции. Поэтому в таком случае компилятор выдаст ошибку о невозможности вернуть ссылку на объект, которым владеет функция.

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

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

Подскажите ещё момент: а в Rust для трэйтов есть имплементации-функций по умолчанию (как в Haskell для тайпклассов)?
а в Rust для трэйтов есть имплементации-функций по умолчанию

есть https://doc.rust-lang.org/book/ch10-02-traits.html#default-implementations


Если нужно перегрузки дженериков делать, по типу с++, то есть ещё такое
https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md но это ещё unstable наверное.

тут 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
}
> со всякой нетипизируемой шаблонной магией

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

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

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

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

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

там еще и язык макросов отдельный, чтобы медом не казалось
НЛО прилетело и опубликовало эту надпись здесь
> Но это всё равно будет проверяться компилятором после инстанциирования.

А в чём вы видите проблему при этом?

> Ударит ли вас компилятор по рукам, если вы концептами, SFINAE или ещё как потребуете только operator< или operator>?

Ээээ… Что значит «ударит ли по рукам» если код не скомпилится?
А в чём вы видите проблему при этом?

В том, что непонятно при использовании функции, связана ли проблема с тем, что функция неправильно вызвана, или с тем, что сама обобщённая шаблонная функция криво написана.

хм… Вообще, такое возможно в плохо документированном проекте, но на практике я с таким не сталкивался. Ключевое в использовании шаблонов — чётко прописывать/понимать/документировать (в широком смысле, — даже просто внятным кодом) интерфейсы.
Ну, хотя, конечно, если бы компилер тут помогал, это было б здорово, да. Писал уже об этом в другом коменте.

Документация устаревает, документация врёт, документация не проверяется компилятором. Типы как-то надёжнее будут.

Верно, но если вы работаете только через пред.описанный интерфейс и проверяете тип на соответствие ему (и по правильному это — документация, её я имел в виду, а вовсе не коменты), всё получается без всяких трудностей и code evolution-related проблем.

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

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

Без дополнительных телодвижений — да, это так.

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

На практике предположу, что если это выглядит проблемой — вероятно, что-то не то со стилем написания кода, в частности с его декомпозицией. Такой код скорее всего уже будет трудно понимать.
Что имеется в виду под «проверял компилятор»? У меня все строго типизировано и всё собирается-проверяется статически компилятором, виртуальных функций нигде нет вообще. Это считается за «проверял компилятор»?

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

Компилятор. Наследуете его от нужного базового класса и переопределяете нужные методы, оставляете при нужде что-то из базового или вызываете его где надо. Не заданные в базовом, которые должны быть заданы в дочернем (обычно такое будет когда базовый близок к корневому классу иерархии наследования) даст ворнинг при компиляции при обращении другого кода к интерфейсному методу (он определён как deprecated c доп.месседжем) и ошибку при линковке.
НЛО прилетело и опубликовало эту надпись здесь

Вот так будет на Rust (просто для справки):


fn max3<T>(a: T, b: T, c: T) -> T
where
    T: PartialOrd
{
    if b > a {
        if b < c {c} else {b}
    } else {
        if a < c {c} else {a}
    }
}

Это всё, конечно, замечательно, но, во-первых, дженерики в Rust работают без наследования, которое ещё нужно девиртуализировать, а во-вторых, что-то вроде Send в C++ невозможно.

> без наследования, которое ещё нужно девиртуализировать

Откуда взялась девиртуализация? Обычное статическое наследование, никаких виртуалов…

> что-то вроде Send в C++ невозможно.

Честно пытался понять, что это, перечитывал несколько раз, но описание назначения и функционала оказалось за гранью моих скромных телепатических способностей.
ps: пока ещё все виденные мной утверждения «В С++ это сделать невозможно» на проверку следовало читать «я не знаю, как это сделать». Как обычно, не настаиваю, что сейчас именно такой случай.
Честно пытался понять, что это, перечитывал несколько раз, но описание назначения и функционала оказалось за гранью моих скромных телепатических способностей.
ps: пока ещё все виденные мной утверждения «В С++ это сделать невозможно» на проверку следовало читать «я не знаю, как это сделать». Как обычно, не настаиваю, что сейчас именно такой случай.

Send — это маркер для типов, которые можно безопасно пересылать из одного потока в другой. Это unsafe трейт, т. е. его можно реализовать вручную, но это требует unsafe кода. В силу того, что это авто-трейт, этот трейт реализуется для типа автоматически, если его реализуют все составляющие типа. Это работает со всеми типами, в том числе и с анонимными сгенерированными типами замыканий. В качестве примера использования можно привести std::thread::spawn, функция для, собственно, запуска потоков. В качестве аргумента она принимает некую функцию, которую можно вызвать без аргументов и получить значение некоторого типа. На тип функции и на тип возвращаемого ею значения наложено ограничение Send, поэтому её нельзя вызвать с типами, значения которых небезопасно пересылать между потоками (как Rc, например, который является потоконебезопасным указателем со счётчиком ссылок).

Ага… В ванильной STL такого нет, да. Но если вы прям очень хотите это иметь в своём проекте, можно сделать обёртку на нужными функциями, где проверять наличие у передаваемых типов аналогичного трейта. Что здесь невозможного?

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

  1. Нет уверенности, что нигде в коде не спрятался вызов необёрнутой функции.
  2. Невозможно проверить на Send локальные переменные сопрограмм.

cppcoro::task foo() {
    bar bar;
    co_await 10s;
    bar.baz(); // UB если bar - не Send
}

Да, я имел ввиду, что далеко не все, что могут делать шаблоны можно "типизировать", то есть выразить в системе типов (Раста). Кое что с помощью обобщенных типов нельзя сделать, что можно с помощью шаблонов.

А как на Rust реализуется граф?
Пусть для определённости будет Control Flow Graph IR программы (сильно разряженный, направленный граф с циклами, без необходимости многопоточного использования)?

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

Если делать граф на safe Rust — то у самого графа должен быть список Rc на вершины, у вершин — Rc на дуги, а у дуг — Weak на вершины. В отличии от двусвязного списка, тут можно построить иерархию владения, а потому подобное представление возможно, пусть и не вполне оптимально.

А почему та же техника не подойдёт для двусвязного списка:
— прямая дуга, та которая next — владение (или Rc ссылка) на элемент.
— обратная дуга, та которая prev — Weak ссылка?

П

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

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

А на сколько это будет неоптимально, в сравнении с условным C, разумеется примерно, в 1.5 \ 3 \ 10 раз?
(я просто сначала подумал, что варианта «немного неоптимально» нет, и есть только вариант «через unsafe»)
Здесь «двусвязный список» можно заменить на любую конструкцию.

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

Для однопоточного варианта.


3 слова для подсчета сильных и слабых ссылок и borrow flag на каждую ноду. Неатомарный inc при создании указателя на ноду. Неатомарный dec и ветвление при удалении указателя на ноду. Неатомарное чтение borrow flag и ветвление при чтении данных ноды. Дополнительно неатомарная запись в borrow flag при начале и конце записи данных ноды.


Многопоточный двусвязный список не рассматриваю — это сложно везде.

А вы когда учебник по квантовой физике читаете, тоже на авторитет не полагаетесь? или, скажем, ПДД...

Если для вас квантовая физика — это какая-то магия, в которой нужно полагаться на авторитет, то вам наука явно не подходит как род занятий.

А вы все выкладки и все эксперименты сами повторяете и воспроизводите?

НЛО прилетело и опубликовало эту надпись здесь

Конечно приходится полагаться на авторитет. Точно так же как мы верим создателям компиляторов, библиотек и ОС. Ибо знать все не возможно, какие-то базовые штуки университетской программы, которые разжеваны из года в год поколениями студентов на лекция и лабах — это одно. А проверять все выкладки в статьях которые я просматриваю в большом количестве, или повторять эксперименты, которые можно сделать в лучшем случае в двух лабораториях мира — это другое. Бывают печальные случаи что через 5, 10 или 15 лет находят ошибки в научных статьях. Естественно ровно одному человеку на слово не верят, т.к. он может сделать ошибку по невнимательности или по злому умыслу. Но в целом научному сообществу и процессу приходится верить. Плюс большинство вещей проверяются косвенно. Типа использовали метод Х и получили то что надо => метод Х вроде как правильный. Но когда в учебнике написано что таким-то чуваком был сделан такой-то эксперимент, то приходится верить учебнику. А вот новостным помойкам я не верю, они свой авторитет не заслужили.

В 99,99% случаев никто в здравом уме и трезвой памяти не станет решать типовые и давно решенные задачи, когда уже есть множество готовых проверенных решений в виде STL, Boost, Poco и да-тысячи-их-на-любую-потребность.

Сколько в мире C++ реализаций стандартных библиотек и компиляторов?


это с какими полезными и удобными возможностями С++ придётся неминуемо расстаться при переходе на раст.

Вычисления времени компиляции? В конце концов RFC2000 всё ещё пилят. С другой стороны у нас есть макросы и процедурные макросы. Через последние можно делать практически что угодно (да хоть дум на найтмаре запускайте). От классического ООП придётся отказаться (хотя не уверен, что это плохо). Попробуйте дополнить список, мне действительно интересно, что же такого я не могу делать в Rust, но смог бы в C++.

НЛО прилетело и опубликовало эту надпись здесь
А как же шаблончики?

А нафига они нужны с тайпчеком после раскрытия?

Например новые типы определять во время компиляции. Как сделать функцию конкатенации std::array на расте?

А в чём, собственно, проблема?

Проверка копирования типов тоже, видимо не требуется. А если там в массиве Т — владеющие объекты, то при дропе получим двойное освобождение?

В исходнике массив копируется через core::ptr::write (memcpy)
А если там в массиве Т — владеющие объекты, то при дропе получим двойное освобождение?

Опять забыли прочитать документацию? ptr::write мувает src в dst.

А если там в массиве Т — владеющие объекты, то при дропе получим двойное освобождение?

С чего бы? ptr::write принимает второй параметр по значению же. Это автоматически означает, что деструктор для него вызываться не будет.

В идеале нужны какие-то const generics, только не те что предлагают стабилизировать на следующем этапе. Язык трейтов он конечно тьюринг полный, только очень стрёмный, поэтому интересно уметь поднимать const fn на уровень типов.

В идеале это, конечно, хотелось бы на const generics написать, но там тогда получается что-то вроде fn concat_arrays<T, const N: usize, const M: usize>(a: [T; N], b: [T; M]) -> [T; N + M], т. е. значение, зависящее от обобщённого параметра, что компилятор Rust пока что совершенно не умеет обрабатывать.

Об этом я и говорил, плюсовые шаблоны такое умеют

У них задача легче, т.к. M и N на момент раскрытия шаблона известны.

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

ну и ответ что всё таки не только job security.
НЛО прилетело и опубликовало эту надпись здесь

И при этом почти полное отсутствие библиотек, и фактическое отсутствие менеджера зависимостей...

НЛО прилетело и опубликовало эту надпись здесь

А на каком этапе они проверяются? Т.е. например есть такое


template<int x, typename F> 
void g(F f) {
  static_assert(f(x) > 0, "ducks");
}

int main() {
    g<3>([](int x) { return 2 * x; });
}

Кроме нормальной типизации что F это функция как много надо ещё будет доказывать?

НЛО прилетело и опубликовало эту надпись здесь

Спасибо, а что делает Refl? Он пытается вычислить f(3)? Есть ли ограничение что f должно завершатся, или это проверяется экспериментальным путём?

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

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

> компилятор не проверяет, что те проверки, которые вы добавили в её сигнатуру, на самом деле соответствуют её телу

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

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

Бывает, конечно, но тогда же просто проект не соберётся и всё. ::std::enable_if или static_assert() для того и нужны.
НЛО прилетело и опубликовало эту надпись здесь
назойливый двусвязный список, который бывает невозможно выразить в безопасном Rust
В безопасном тоже можно сделать используя Rc<RefCell> или Arc<Mutex> в зависимости от задачи.
Но зачем, ведь есть реализация списка в стандартной библиотеке.
Rust решил оседлать нишу сверхбыстрого и сверхнадежного ПО. Возможно это ему удастся. Но это ниша узкая и за ее пределами ему будет трудно подвинуть C/C++ и в силу их огромного легаси, и в силу бОльших экосистем, а самое главное в силу неочевидной необходимости такой его сложности за пределами той самой ниши.

В результате может получиться так, что разработчика под Rust будет тяжело найти, а это может дать такую отрицательную обратную связь, что он может вообще «не взлететь».
Если минус за то, что это ниша на самом деле широкая, то я спорить не буду. Но пока мне так не кажется.
А иначе — минус от обиды за судьбу Rustа?
Я думаю минус — за глупость. :(

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


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

(ведь скажут, что это растоманы такие вредные, всех минусуют, кто с ними не согласен)

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

Минус не очень хорошая штука — он влияет на рейтинг и на видимость комментария. Я обычно просто несогласие выражаю в комментарии, либо плюсую ответы тех, с кем согласен. Минусую только те, где явно есть провокации, деструктивные попытки съехать на личности, оскорбления и пр. То есть я воспринимаю минус как "убрать этот комментарий", а не как "выражаю несогласение с точкой зрения автора". К сожалению система оценок Хабра и ее влияние принуждают к этом.

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

Rust хорошо себя показывает и в тех областях, где традиционно используется какая-нибудь Java
Так почти любой развитой ЯП хорошо покажет себя в задачах Джавы (не в упрек последней). Но там ведь основной вопрос — это баланс надежности, простоты и эффективности. А от очень многих я слышу, что Rust им непривычен / труден / странен. Конечно, любой Тьюринг-полный язык можно применить в любой области, особенно если этот язык нравится ) Обычно, кстати, так и делают — изобретают сначала ЯП для одних целей, а потом стараются максимально расширить область его применения. Здесь все ок. Просто решать вопрос о применении языка будут не разработчики Раста, а бизнес, а там эмоции одни — деньги, деньги, деньги.

Вообщем, будем посмотреть. И хотелось бы, хоть я и не растоман, чтобы он все-таки «взлетел» по-настоящему.

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

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

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

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

Каким образом? Доверять надёжность мешкам с мясом в принципе нельзя.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории