Комментарии 110
Да, когда я увидел этот язык мне он тоже сначала не понравился. Я не думал что он может быть быстрым и при этом безопасным. Сейчас Rust это мой любимый язык.
Какое-то время уже присматриваюсь к Rust, задавал соответствующие вопросы, но так и не осознал пока в чем же он лучше/удобнее того же Си. Потому что довольно часто слышу что его сейчас предпочитают тому же Си в embedded разработке. И это не упрёк, мне действительно интересно, но когда я листаю код на github он выглядит для меня слишком замысловато для довольно простых действий, вероятно к нему нужно долго привыкать.
Знаете, на мой взгляд он нисколько не удобней си, скорее наоборот. Однако даёт несколько иной взгляд на программирование и вот это мне очень нравится.
Если на Rust писать как на Си, процедурно, не используя высокоуровневых возможностей, то он очень похож на Си, в том числе синтаксисом. В этом режиме он добавляет к Си несколько удобных вещей: ссылки на подмассив массива (сразу с длиной), проверку валидности времени жизни ссылок, работу с UTF-8, автоматический free для malloc. Под unsafe становятся доступны сырые указатели и открываются все опасные возможности Си.
Система типов Rust похожа на Haskell, а возможности структур аналогичны возможностям ООП-языков. Получается как C + Haskell + C# в одном, можно использовать возможности любого из языков, а можно все три одновременно, как больше нравится.
в чем же он лучше/удобнее того же Си
Раст позволяет ловить на этапе компиляции ошибки, которые в С превращались бы в отстреленные ноги.
Не нужно писать типы у каждой переменной, явно помечаются изменяемые значения, а не наоборот, цикл по массиву — это именно цикл по массиву, а не танец с ручной инкрементацией переменной, местный аналог switch проверяет полноту покрытия и работает со строками, проигнорировать ошибку невозможно, не нужно вызывать free руками, в if-ах и while не нужно писать скобочки вокруг условия.
Да, это всё в основном поверхностные и синтаксические различия, но это то, что лично мне бросается в глаза при необходимости что-то писать на C (с учётом того, что Rust сейчас мой рабочий язык) и что раздражает.
Ничто не агитирует против раста так надёжно как его фанбои рассказывающие об идеальности языка с упорством достойным свидетелей Иеговы.
Но он же идеален...))
Почему? Она сильнее чем сишная.
Нет идеальных языков.
Какъ же такъ, а Хаскель?
Если у раста она слабая, то что тогда по-вашему сильная?
Система типов Idris например.
А чем она сильнее?
Почитал что это такое. Штука, действительно, интересная. Вот только к силе типизации она относится косвенно.
Насколько я понимаю, она будет работать только в языках с сильной типизацией, но и времена жизни в Расте будут выполнять свою функцию только при тех же условиях.
у раста система типов ещё и слабая
А у, скажем, плюсов, она, по вашему мнению, вообще мнимая?
Легко быть фаном того, что отлично работает. Вот чтобы быть преданным фаном плюсов и старательно игнорировать раст - вот тут уже по истине нужно быть фанатичным
Мне понравилось -- было непросто, но очень лаконичный код дал гору функционала и прекрасные сообщения об ошибках. Сам принцип вариативного анализа, который заставляет обработать все ошибки и крайние случаи -- это реально впечатляет. Получается код, который чем-то похож на функциональные подходы -- уверенность в его надежности намного больше, чем обычно. А сообщения об ошибках сами собой получаются на порядок более человекопонятными, хотя ты о них даже не думал.
egui + eframe. Работают на десктопных ОС и на вебе. Сайт https://www.egui.rs/ написан на egui и является демкой.
Где вариант "пробовал, теперь пишу преимущественно на Rust"?
C Rust заморочка - чтобы вникнуть в тонкости - нужно на нем поработать. А его рейтинг - менее 1%, т.е. он еще не набрал а лишь набирает популярность. Ну и главный момент - будет ли он и далее набирать популярность? Вот, уже на подходе новый еще более крутой ЯП - Mojo. Не получится ли так, что только привык к Rust, соглашаясь работать за копейки (т.к. лишь изучаешь язык) - нужно переучиваться на Mojo?
Не сказал бы что он прям набирает популярность, вакансий крайне мало, а те что есть в основном крипта. То что Mojo более крутой еще более сомнительно
Ты пишешь о том что невышедший язык лучше чем Rust... Понятно.
Я совсем не фата раста, т.к. мне на нём сложно писать, но профит от его использования хотя бы понятен - он не позволяет тебе делать многие небезопасные вещи, в т.ч. позволяет безопасно работать с памятью без GC. А в чём крутость питона с типами (если я правильно понял суть Mojo), это же просто очередной язык с GC
Там владение вроде будет, как в расте.
Насколько я понял, оно будет опциональным, что не позволяет убрать GC. Вот пример с официального сайта:
def reorder_and_process(owned x: HugeArray):
sort(x) # Update in place
give_away(x^) # Transfer ownership
print(x[0]) # Error: ‘x’ moved away!
Поэтому особого смысла в его использовании я не вижу.
чтобы вникнуть в тонкости - нужно на нем поработать
Мне думается, это утверждение верно для любого X, причём речь не только о программировании.
Так же кроме декламаций просьба написать конкретику, а именно - вот на этом языке делаю так а тут смотрите как.
Я, если так можно выразиться, прошёл базовый курс по официальной книжке. Точнее, пробежал. Больше всего меня впечатлила глава 17, где на конкретном примере сравниваются 2 подхода к ООП-разработке.
Мне кажется, что были бы полезны примеры того, как надо и как НЕ надо делать в Rust'е. Условно, берётся некая задачка и реализуется на каком-то ЯП. Затем она переносится с минимально возможными переработками на Rust. Потом эта же задача реализуется "как надо" с нуля на Rust, с учётом его особенностей. И подробный разбор - что, почему и как. Чтобы сразу приучать мыслить по-растовски.
Хотя, это, наверное, относится к любому рекламируемому ЯП.
Черт, а можете про симулятор роста плесени рассказать?
Можете посмотреть пост об этом, там внизу есть ссылка на демку и на исходники.
Если коротко: на по экрану хаотически движутся частицы, а в центре находится целевой неподвижный объект. Если частица оказывается рядом с целевым объектом, она перестаёт двигаться и становится целевым неподвижным объектом. Направление движения каждой частицы выбирается случайно на каждом цикле обновления (броуновское движение). Эмуляция выполняется до тех пор, пока все частицы не станут целевыми и неподвижными.
По какой-то причине JS-версия чаще начинает заполнять правый нижний угол
Причина проста - активные точки чаще двигаются влево и вверх, чем вправо и вниз, т.е. чаще "набегают" на конструкцию справа и снизу. Почему так? Покажу на примере горизонтальных перемещений: пусть у нас строка "...001100...", где 1 - активные точки, у нас тут их две штуки подряд. Горизонтальная строка обрабатывается слева направо. Возможные пары перемещений: LL, LR. Невозможен RR, вторая точка блокирует первую. Вот отсюда и "перекос".
Реализацию на Rust не смотрел, не разумею Rust.
Он необычный.
Он неисчерпаем.
Вот это-то и пугает в масштабе команды 5+ человек.
Rust, конечно, крут.
Но, лично у меня оставил не лучшие впечатления.
Очень сложный язык. Причем не из-за концепции владения переменной, или еще каких, а главным образом из-за макросов. Каждая библиотека пытается реализовать свой набор макросов, которые надо знать и уметь применять. В результате - очень много "магии" и синтаксического сахара пытаются получить. А по факту - шаг в сторону и не работает. Хорошие сообщения об ошибках выручают, но далеко не всегда. Очень много неочевидных моментов и сложностей возникает. В результате - порог входа становится высоким.
Кроме того, тип переменной вычисляется не только по левой части, но и по тому, как эта переменная потом используется. С этим конечно можно бороться, устанавливая тип каждый раз самостоятельно. Но это не выход - язык старается ограничиться простым let
и избавляться от явного указания типов.
И ресурсов это все требует - просто море.
Десятки гигабайт артефактов сборки (60GB в папке target
- не предел).
Сборка в течении не секунд-минут, а десятков минут, а то и часов на современных системах ("на холодную", без кешей сборки). Впрочем, с "прогретым" кешем собирается достаточно быстро.
Оперативной памяти - тоже требуется немало.
В общем неоднозначные впечатления Rust оставил.
У меня довольно большое web-приложение (ядро биржи) на 150 000+ строк кода собирается 15 минут с нуля на моём ноутбуке (релизная сборка, jobs = 4).
На каком web-фреймворке написано?
Погодите, 150к loc это примерно 6мб? Это довольно немного. Для сравнения Qt - 1.2 гб
У меня был относительно небольшой проект (1,4МБ папка src
весит), у которого достаточно много зависимостей (50+ прямых зависимостей, 400+ объектов сборки). Отсюда и длительная сборка без кеша и большой размер этого самого кеша сборки. Да и размер - чистая сборка (debug) дает около 6GB артефактов на этом проекте, что крайне много, на мой взгляд.
Впрочем, и другие Rust проекты, с которым приходилось работать, тоже отличались аппетитом к дисковому пространству. Даже самые простые проекты на несколько гигов разрастаются очень быстро.
Сюда же накладываются особенности компилятора Rust - в каталоге артефактов остаются предыдущие версии зависимостей и артефакты собранные предыдущими версиями Rust (что может добавлять проблем, если требуется использовать ночную версию компилятора).
Вот папка target
и разрастается еще сильнее.
Каждая библиотека пытается реализовать свой набор макросов, которые надо знать и уметь применять.
А можно примеров? Ну сериализация (#[derive(Serialize, Deserialize)]
) понятно, но такие макросы легко воспринимаются после стандартных дерайвов (Debug, Clone и т.д.). Да и как-то не припоминаю чтобы серде неожиданно ломалось, так что тут тоже послушал бы. Ну #[tokio::main]
без которого можно обойтись и который никакой магии не делает. Ну ладно tracing. А ещё?
Кроме того, тип переменной вычисляется не только по левой части, но и по тому, как эта переменная потом используется.
Да, есть такое, но чем оно мешает? Есть наглядные примеры когда такой вывод мог как-то неочевидно поломать логику?
Я еще при изучении Rust Book обратил внимания на макросы и на возможные неопределенности в типах переменных. В процессе же работы с Rust я понял, что в целом, вывод типов, при всех своих возможностях, является источником огромного числа проблем. Ну и подтвердил проблемность макросов на практике.
Я не могу сказать, что макросы или вывод типов ломают именно логику приложения. Они ломают компилируемость приложения, что особенно заметно при обновлении зависимостей. И зачастую, чтоб разобраться в источнике проблемы, приходится очень нетривиальные усилия приложить. Когда все работает - это отлично. Когда уже понял в чем проблема и исправил - это тоже замечательно и кажется все таким очевидным. Но найти в чем проблема - зачастую очень нетривиальная задача.
Да, в других языках, обновление зависимостей тоже могут сломать компиляцию. Но из моего опыта, это случается гораздо реже, чем в Rust. И ошибки гораздо проще править – просто потому что намного проще понять что не так.
А теперь к примерам.
Sylvia framework - используется для написания смарт-контрактов на WebAssembly под Comsos SDK).
Вообще, это отличный пример синтаксического сахара, который мало что дает, кроме лишней головной боли. В частности, макрос генерирует типы, используемые напрямую разработчиком и со строго определенными именами. И при этом требует наличия типа ошибки со строго определенным именем в этом же модуле. Правда в последних версиях вместо строго определенного имени надо указывать (очередным макросом) нужный тип ошибки – тоже не лучшее решение.
В данном случае из сообщения ошибки сразу было понятно что не так. И стало понятно зачем в примерах определяется "лишний" тип как алиас к существующему. С новой версии пришлось покопать, почему ранее определенный тип больше не видится в макросе. Оказалось, что дополнительным макросом этот тип надо указывать (зато теперь можно обойтись стандартным типом).
SQLx - либа для работы с БД. Миграции, очень базовая ORM.
В целом отличная библиотека. Если не использовать макросы. А судя по объему документации к макросам – это основной предполагаемый способ использования. Или самый проблемный кусок кода.
Вообще, макросы, проверяющие синтаксис запроса при компиляции – очень крутая идея. И генерация оберток для запросов в макросе – тоже очень удобно. В теории. На практике – простая необходимость задавать правильную БД проекта нужной версии просто для компиляции или работы в IDE – это очень большая проблема. Потому как получается зависимость от типа СУБД, от проведенных миграций на этой БД, и, судя по всему, от версии СУБД (судя по тому, что простейшие примеры из документации SQLx у меня просто не заработали, хотя пример был 1-в-1 – та же СУБД, дословно скопированный пример). Потом в документации встретил что-то вроде «попробуйте так, если не заработает, попробуйте так. Если все плохо – попробуйте имена полям запроса задать по таким правилам, мы вырубим свою сверх логику определения типов и тогда должно заработать».
Вообще, интересная картина выходит, если используются авто-миграции в проекте. При изменении БД – в проект добавляется миграция. Но скомпилировать проект ты не сможешь, пока вручную не проведешь миграцию БД (если есть запросы к новой части БД). Благо, что есть внешняя утилита, которая умеет выполнять миграции (что тот еще костыль). В командной работе – это все очень неудобно. Обновил исходники, конфликтов нет. А компиляция сломалась. А уж как DevOps-ы радуются необходимости актуальной БД в нужной версии СУБД просто для компиляции проекта...
Тут проблемы быстро всплыли еще на этапе изучения библиотеки в проекте-песочнице. Благо, что без макросов, все работает не хуже. Единственное - документация без макросов сводится к тривиальному "Этот метод выполняет запрос".
Axum - фреймворк для построения веб-приложений.
В целом отличный фреймворк для бекенда.
Но буквально вчера обновление axum принесло «радости» на под дня. Просто handler-ы запросов перестали выводиться в нужный тип. Хотя все конструкции, используемые типы, все осталось на месте. Примеры с этими конструкциями тоже на месте и делают тоже самое, что и раньше. Но компилятор упорно говорит, что мой handler не удовлетворяет тому типу, что должен быть. Как оказалось – теперь порядок аргументов в handler должен быть строго определенным. И аргумент с заголовком должен быть выше аргумента с телом запроса. Тривиальнейшее исправление, но чтобы до него дойти - пришлось потратить очень много времени.
Это далеко не все случаи, а только то, с чем столкнулся за последнее время.
Бывали ошибки на пол-экрана что не соответсвую определенному trait и которые решались добавлением #[derive(Debug)]
к типу (в ошибке ни слова про этот Debug, как и в документации, при поверхностном чтении, не увидел отсылок к этому макросу). Выяснил только при дословном сравнении с работающим примером, что у меня не определен этот макрос к моему типу. Впрочем, это было достаточно давно и в деталях могу ошибаться.
Встречались макросы, который толи надо явно импортировать, толи не надо (а надо просто подключить зависимость). Так и не понял, что это было. Пришлось добавить неиспользуемый импорт, чтобы появился нужный макрос в пространстве имен и компиляция заработала (хотя IDE и компилятор упорно предлагали убрать этот импорт как неиспользуемый).
С типами проще. IDE при неопределенности в типе просто не дает подсказок в авто-дополнении. Опять же, с SQLx и их макросами я на это наткнулся. При этом проект может успешно компилироваться и выполняться. Но IDE не может понять что там за типы (использую VS Code с официальным дополнением и всеми обновлениями) и выдать подсказки, что с этим объектом делать дальше.
Вообще, в Rust основным источником информации является документация к проекту и примеры кода. Причем примеры кода я бы поставил на 1е место. Просто потому, что документацию зачастую надо изучать целиком, чтобы иметь цельную картину. Изучение исходных кодов библиотек затруднено (что зачастую сильно выручает в других языках) – опять же повсеместными макросами и выводом типов (да и IDE зачастую не может сказать откуда тот или иной макрос взялся).
Обычно для изучения библиотеки я делаю базовое изучение документации (Quick Start или хотя бы ReadMe), нахождение простейших примеров, запуск примеров в песочнице и изучение возможностей библиотеки на базе работающего примера. Но с Rust подход "попробовать пощупать в песочнице" работает с переменным успехом.
Поэтому и говорю, что Rust оставил смешанные впечатления. При всех своих достоинствах, с ним очень много проблем всплывает на ровном месте.
да, я помню таким образом просидел над axum'om пол часа, пока не нашел этот вопрос на гитхабе)
это было не вчера, а когда я только начинал писать на axum'e.
А вот я до загуглить как-то не дошел...
Ошибка уж слишком общая была - the trait .. is not implemented
.
Но нашел решение в описании к релизу...
Впрочем, сейчас загуглил - вышел на макрос axum::debug_handler
, которые более человеческие ошибки генерит. И он прямым текстом говорит в моей ситуации:
Json<_>
consumes the request body and thus must be the last argument to the handler function
Спасибо за подробный ответ и примеры! Спорить не буду, проблемы случаются. Но всё-таки не могу согласиться с изначальной формулировкой про макросы в "каждой библиотеке". Не согласен даже с "в каждой второй/третьей". (:
А теперь подробнее:
в целом, вывод типов, при всех своих возможностях, является источником огромного числа проблем.
Прям огромного?.. В любом случае, считаю, что удобства перевешивают. Начиная с банальной возможности не указывать тип в штуках вроде .collect<SomeTime>()
если он понятен из контекста. Считаю, что в расте пошли на достаточно удачный компромисс: сигнатуры функциям писать обязательно, а внутри типы выводятся. Так-то существуют языки (например, хаскель), которые не заставляют и сигнатуры прописывать.
Ну и всё-таки я хотел бы увидеть примеры проблем вывода типов не связанные с макросами. Отсутствующие подсказки в IDE — это скорее проблема (относительно) сырых инструментов, а не вывода типов.
Макросы — да, мощный инструмент и их использование несёт определённые последствия. Но как правило ими всё-таки не злоупотребляют без необходимости и без них было бы хуже. В С++ в подобных случаях используется метапрограммирование на шаблонах с подобными недостатками: замедление компиляции и порой невнятные сообщения об ошибках.
Sylvia
Конкретно с этой библиотекой дела не имел, но мне тоже кажется, что в блокчейн-фреймворках макросами несколько злоупотребляют. Думаю, что тут есть желание дать пользователю подобие DSL, не уверен, что оно прям всегда оправдано. Ну и всё-таки в макросе можно сделать более удачные сообщения об ошибках, но это дополнительная работа, само-собой оно не получается. Для "фундаментальных" библиотек вроде серде этим заморачиваются, для менее популярных штук очевидно нет.
SQLx
Пока не доводилось использовать, пользовался только дизелем, так что особо прокомментировать не могу. В дизеле тоже есть макросы, но по минимуму. Ну и я всё-таки считаю, что проверка запросов на этапе компиляции того стоит. Кстати, в ридми написано "Compile-time checked queries (if you want)".
Axum
С этой библиотекой пока только немного экспериментировал, в основном использовал актикс. Но разве описанная проблема в макросах или выводе типов?.. Разве если тип руками был написан в духе Handler<X, Y, Z>
, но в новой версии Y
нужно было бы реализовать дополнительный или другой трейт, то было бы не то же самое?
Встречались макросы, который толи надо явно импортировать, толи не надо (а надо просто подключить зависимость). Так и не понял, что это было.
Любопытно, а кода не осталось под рукой случайно? Интересно было бы разобраться.
Не согласен даже с "в каждой второй/третьей". (:
"Все библиотеки" - да не реализуют, согласен, это банальное преувеличение.
А вот сколько-нибудь крупные - почти все реализуют. На вскидку - tokio, axum (тут правда отдельной фичей подключаются), тот же SQLx или Diesel.
Прям огромного?.. В любом случае, считаю, что удобства перевешивают. Начиная с банальной возможности не указывать тип в штуках вроде
.collect<SomeTime>()
если он понятен из контекста.
В других языках меньше борьбы с компилятором, проще понимать что именно от тебя хотят и как это исправить. Проблемы с компилятором может и не реже встречаются, но уж точно проще решаются, на сколько я могу судить.
С одной стороны определенное удобство есть, с этим не спорю. Но стоят ли того эти проблемы - не уверен. Особенно на крупном проекте, на мой взгляд, надежность будет важнее.
Да и не уникальная фишка Rust-а это. В той же Java тип далеко не всегда надо указывать. Уже лет 5 как можно не указывать (с 2018 года). Для локальных переменных можно обойтись с var
, а указание типа коллекций и прочего - можно было опустить и того раньше, если это понятно из контекста. Не говоря уже про разные Golang / JavaScript / TypeScript.
Тот же haskell я только в универе изучал, но с ним не помню подобных проблем, как с Rust. Впрочем, это было очень давно, и в очень ограниченном объеме. Так что не показательно абсолютно.
Понятное дело, что сейчас большая часть проблем - следствие быстрого развития экосистемы Rust. И сравниваю я "проблемность" в написании кода не с C/C++, а скорее с Java или Golang, что тоже не совсем верно. Вторая часть проблем - недостаток опыта в работе с Rust, в работе используемых библиотек и т.д. Но у меня достаточно много опыта с другими языками (на вскидку - C# / Java / Golang / JavaScript / TypeScript), чтобы сложить свое мнение о большей проблемности Rust. Причем это мнение сложилось еще на этапе изучения Rust book, дальнейший опыт работы только подтвердил это мнение.
Ну и всё-таки я хотел бы увидеть примеры проблем вывода типов не связанные с макросами.
На вскидку не приведу примеров именно с типом переменной. Помнится в Rust book, во 2й главе описывалась подобная проблема (Programming a Guessing Game). Но видать, уже поменяли, что поведение Rust, что саму главу. На сколько могу судить, сейчас Rust именно что требует в такой ситуации явное указание типа.
Впрочем, с выводом типов мне хватает и проблем вида the trait .. is not implemented
- очень "весело" вникать, что именно не хватает, чтобы стало implemented
. Хотелось был "глянул сорцы библиотеки - сделал что требуется". Но это редко помогает. Зачастую приходится примеры смотреть, где это работает, вникать как и почему работает. И постепенно доводить свой код до работоспособного вида.
Отсутствующие подсказки в IDE — это скорее проблема (относительно) сырых инструментов, а не вывода типов.
А сколько должно пройти лет, чтобы инструмент перестал быть сырым? Сколько лет экосистема Rust активно развивается? Сам Rust начинает свое развитие с 2006 года. В 2015 году вышла первая стабильная версия (Rust 1.0). Т.е. за 8 лет, не смотря на весь бум развития и хайп вокруг языка, основные инструменты разработки остаются сырыми? Как бы проблемы бывают у всех языков и у всех инструментов (лично находил в релизах Golang ошибки вида "по мнению IDE возвращается один тип, по мнению компилятора - другой"). Но это именно что случайные ошибки. С Rust получается не случайные ошибки, а системные проблемы (впрочем, на сколько мне известно, системные проблемы у Rust имеются (организационного характера)).
Sylvia. ...мне тоже кажется, что в блокчейн-фреймворках макросами несколько злоупотребляют.
Именно что злоупотребляют. Изучал и другие системы смарт-контрактов на базе WebAssembly - такое впечатление сложилось практически о всех. Wasmd (CosmWasm) был одним из самых адекватных, если не использовать Sylvia (благо, что это опциональный фреймворк, "поверх" стандартных наработок CosmWasm).
Впрочем, для WebAssembly так или иначе придется использовать макросы. Просто потому, что для передачи в WASM сколько-нибудь сложных данных (например, тех же строк) надо выполнить определенные заморочки как со стороны WASM, так и со стороны хоста. И макросы могут эти заморочки взять на себя (пускай и нужно согласованное API взаимодействия между WASM и хостом).
SQLx. Ну и я всё-таки считаю, что проверка запросов на этапе компиляции того стоит. Кстати, в ридми написано "Compile-time checked queries (if you want)".
Полезная фича, но сорцы начинают зависеть и от схемы в БД, и от используемой СУБД. Будь это чистой кодогенерацией: подключился к БД - нагенерил код - используешь. Я бы сказал - да, мега-фича (особенно если опционально). Но в режиме постоянного подключения - скорее вызывает неудобство. Это может быть удобно в случае, если ты один работаешь надо "домашним" проектом, не заморачиваясь ни версионностью БД, ни CI/CD, ни сборкой Docker-образов и т.д. Подправил БД - подправил запросы - работаешь дальше. А в командной разработке, особенно если БД активно развивается - лучше не надо.
И да, не нужны проверки - не используй макросы. Вот и вся опциональность ) Есть просто методы для выполнения запросов. Пускай и с крайне скудной документацией (особенно на фоне описания макросов). Впрочем, из ReadMe видно как их использовать - и этого, по большому счету, достаточно.
Axum. Но разве описанная проблема в макросах или выводе типов?
Понятное дело, что все описанные проблемы - это проблемы конкретных библиотек и их разработчиков. Тут вопрос скорее к Rust, что нет достаточно внятной ошибки. С Golang / Java / C# мне бы тоже сказали "не удовлетворяет интерфейсу" с крайне скудным описанием этого самого интерфейса. Но я могу без проблем посмотреть что за интерфейс и в большинстве случаев быстро исправить. Мне не надо тратить много времени на понимание, в чем именно ошибка заключается.
Именно поэтому Rust и оставил лично у меня смешанные чувства. И хорошая документация с продвинутыми описаниями ошибок тут не помогают. Потому как они следствие сложности работы с типами в Rust, которые пусть и могут упростить ситуацию, но принципиально ее не меняют.
Любопытно, а кода не осталось под рукой случайно? Интересно было бы разобраться.
На сколько помню, это был смарт-контракт, но под какой блокчейн я уже не помню (я тогда изучал как пишутся контракты под разные блокчейны на базе WebAssembly)... Дело было в 2021 году, если не ошибаюсь. Так что даже не факт что получится повторить проблему сейчас. Да и не нашел я проблемных исходников...
А вот сколько-нибудь крупные — почти все реализуют.
Всё ещё хочется поспорить. Мне кажется, что дело скорее в конкретном типе библиотек. С базами данных авторы закономерно хотят дать больше гарантий и тут без макросов сложно, хотя повторюсь — в дизеле их по моим ощущениям поменьше. В актиксе и аксуме можно и так и сяк, причём если мне не изменяет память, то в первом изначально было без макросов, но у альтернативных фреймворков они были и видимо решили тоже добавить. Всё-таки с макросами примеры кода выглядят красивее. А в токио много ли макросов? Тривиальный #[tokio::main]
я бы даже не считал, его и руками написать можно, если хочется. Ещё #[tokio::test]
, но обычные тесты тоже через макрос объявляются. Ну ладно ещё select!
...
Вот несколько примеров без макросов: reqwest, hyper, winit, nphysics2d. На одном из прошлых проектов использовали rusoto для работы с AWS сервисами — макросов не было. Позже амазон написали свою либу (aws-sdk-rust) и тоже без макросов.
В других языках меньше борьбы с компилятором, проще понимать что именно от тебя хотят и как это исправить
То, что раст заставляет бороться с компилятором — это уже мем, хотя обычно подразумевают бороу чекер. Я в прошлом С++ разработчик и вот там тоже бывало весело в хитром шаблонном коде.
Но у меня достаточно много опыта с другими языками (на вскидку — C# / Java / Golang / JavaScript / TypeScript), чтобы сложить свое мнение о большей проблемности Rust. Причем это мнение сложилось еще на этапе изучения Rust book, дальнейший опыт работы только подтвердил это мнение.
Забавно, что с моим опытом ситуация была прямо противоположная: до сих пор не могу нарадоваться тому насколько многие (да почти все!) вещи в расте проще и удобнее. Хотя гибкости плюсов изредка не хватает, да.
А сколько должно пройти лет, чтобы инструмент перестал быть сырым?
Дык, дело не в годах. За растом нет стоит большой корпорации. Мозилла, даже в лучшие времена, не сравнится с эплом (свифт) или майкрософтом (C#), которые могут выкатить сразу язык, богатую библиотеку и инструменты. Сейчас хоть и есть Rust Foundation, но деньгами эта организация явно не завалена. Опять же, сравнить можно и в другую сторону. Через сколько лет после появления языка в С++ образовался более-менее общепризнанный форматтер кода?.. А хотя бы тот же CMake? Который хоть и наиболее популярен, но прям "стандартным" не назовёшь.
rust-analyzer (реализация LSP) написали фактически энтузиасты, изначально вообще один человек. Есть альтернативный плагин для IDE от JetBrains (которым я пользуюсь) — он бесплатный, но подозреваю, что как раз потому что продавать его на данный момент будет весьма сложно. Тем не менее, понемногу ситуация улучшается, в том числе поддержка макросов.
Всё ещё хочется поспорить. Мне кажется, что дело скорее в конкретном типе библиотек. С базами данных авторы закономерно хотят дать больше гарантий и тут без макросов сложно, хотя повторюсь — в дизеле их по моим ощущениям поменьше.
В дизеле кодогенерация есть (всякие #[derive(Queryable, Selectable)]
). Хм... В дизеле кодогенерация есть по БД в виде отдельного инструмента CLI... Надо будет дизель копнуть чуть глубже ) Мне сейчас хотелось найти очень легкую ORM, чтобы просто маппить запросы в объекты (и уметь в миграции в виде просто SQL-запроса) - SQLx для этого отлично подошла.
Я не спорю, что хорошие библиотеки имеют и хорошие макросы. В популярных библиотеках с этим все более-менее хорошо (иначе быстро образуется форк с исправленными косяками и уже форк будет занимать лидирующие позиции). Но все равно, рано и ли поздно придется столкнуться с библиотеками и макросами не лучшего качества - и это будет больно. Впрочем, плохие либы делают больно в любом языке.
Забавно, что с моим опытом ситуация была прямо противоположная
Как я и говорил, я сравниваю не с C/C++, а скорее с Java/Golang. C JS/TS, на мой взгляд, работать скорее даже сложнее, чем с Rust - особенности экосистемы JS/TS. Хотя сами языки заметно проще Rust и именно как языки JS/TS мне очень нравятся. А с C/C++ в продуктовой разработке я дел почти не имел, хотя в универе больше всего именно с C/C++ работал (но учеба в универе - это несколько другой опыт).
Дык, дело не в годах. За растом нет стоит большой корпорации.
Честно сказать не знаю финансового положения Rust Foundation. Может деньгами и не завалены, но и не думаю, что бедствуют.
Сравнивать с C++ некорректно - сейчас сильно другие времена (относительно времен появления C++) и другие требования/стандарты к экосистеме языка.
Под капотом, что в VS Code, что в JetBrains сейчас rust-analyzer. До rust-analyzer был RLS (Rust Language Server), и плагины в VS Code и в JetBrains работали именно с ним. Rust-analyzer сначала появился в виде альтернативного плагина для VS Code, а после официального становления частью Rust, и в JetBrains на него перешли. Возможно, JetBrains сейчас имеет свои фишки (в плане разработки IDE JetBrains не одну собаку съели), но когда я сравнивал VS Code и JetBrains, то особых различий не заметил (после перехода этих IDE на rust-analyzer). А в плане IDE мне VS Code больше нравится - она заметно быстрее работает. Я даже для Java перешел на VS Code (там под капотом eclipse, не знаю правда, на сколько переделанный), хотя IDEA в свое время казалась идеальной IDE (да и сейчас я могу назвать IDEA лучшей IDE для Java).
Честно сказать не знаю финансового положения Rust Foundation. Может деньгами и не завалены, но и не думаю, что бедствуют.
Точных подробностей я тоже не знаю, но из тех новостей, что проскакивают всё совсем не так радужно. Плюс Foundation всё-таки не занимается напрямую разработкой языка, а из непосредственных разработчиков многие трудоустроены в разные компании, которые заинтересованы в расте. Плюс немало делают вообще "волонтёры". Это само по себе не плохо, но не то же самое, когда компания нанимает 100 человек фултам чтобы они инфраструктуру пилили.
Сравнивать с C++ некорректно — сейчас сильно другие времена (относительно времен появления C++) и другие требования/стандарты к экосистеме языка.
Ну почему некорректно? С++ ведь тоже существует и развивается в настоящее время, а с некоторыми вещами до сих пор не очень. Да, необходимость обеспечивать совместимость с легаси всё усложняет, но зато язык весьма популярный, а значит и заинтересованных лиц (с деньгами) больше.
в JetBrains сейчас rust-analyzer.
RLS (Rust Language Server), и плагины… и в JetBrains работали именно с ним.
Нет, это не соответствует действительности. У джетбрейнс свой велосипед, если мы говорим про семейство IDEA. Вот сыроватый Fleet действительно поддерживает LSP.
С++ ведь тоже существует и развивается в настоящее время, а с некоторыми вещами до сих пор не очень.
Про C++ мне сложно судить. Как я понимаю, с C++ больше вопрос легаси и вопрос разнообразия инструментария (исторически сложившегося). Проблема скорее в том, что общепринятого единого тулчейна просто нет. А так или иначе "современный" инструментарий есть.
У джетбрейнс свой велосипед, если мы говорим про семейство IDEA.
Хм... Был уверен, что у них плагин на базе RLS, а потом переделали на базе rust-analyzer. Не LSP, это да. Но на базе этих инструментов. Возможно, их плагин функционально сначала был на уровне RLS (или чуть лучше), а потом его догнали до уровня rust-analyzer (чтобы конкурировать с VS Code).
Я VS Code несколько раз с JetBrains сравнивал для Rust. И особой разницы, или не заметил, или она была вообще в пользу VS Code (когда появился rust-analyzer, а в JetBrains еще не обновили плагин).
Про Fleet слышал (но не щупал). Как я понимаю, это скорее попытка повторить VS Code (с их Remote Development) - легкая и расширяемая IDE с возможностью разработки в контейнере или по SSH.
И про совместную разработку они не забыли, хотя я очень плохо представляю, как это выглядит на практике - код это не документ в GDocs, у него должна сохраняться согласованная структура.
И вроде как они работают над своим аналогом LSP (впрочем, не отказываясь от поддержки LSP). И я верю, что у них выйдет хороший продукт - у JetBrains действительно хорошая экспертиза в разработке IDE (правда, если не растеряли ее за последние года - не сильно интересовался как именно у компании идут дела).
SQLx. Ну и я всё-таки считаю, что проверка запросов на этапе компиляции того стоит. Кстати, в ридми написано "Compile-time checked queries (if you want)".
Полезная фича, но сорцы начинают зависеть и от схемы в БД, и от используемой СУБД. Будь это чистой кодогенерацией: подключился к БД - нагенерил код - используешь. Я бы сказал - да, мега-фича (особенно если опционально). Но в режиме постоянного подключения - скорее вызывает неудобство. Это может быть удобно в случае, если ты один работаешь надо "домашним" проектом, не заморачиваясь ни версионностью БД, ни CI/CD, ни сборкой Docker-образов и т.д. Подправил БД - подправил запросы - работаешь дальше. А в командной разработке, особенно если БД активно развивается - лучше не надо.
Справедливости ради, на днях обнаружил, что у sqlx есть "Offline Mode" - можно выгрузить представление БД в виде JSON, и если DATABASE_URL в env не задано, то будет использоваться этот файл. Что позволяет успешно работать с проектом без постоянного подключения к БД. И в релизе 0.7 (который сейчас готовится) работа в Offline Mode становится приоритетным подходом, что, на мой взгляд, абсолютно оправдано.
collect<SomeTime>()
help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
Rust в целом - прекрасный язык.
Макросы, вывод типов - очень мощные возможности, к этому вопросов нет.
Но реальность использования такова, что без общепринятых и устоявшихся практик, эти мощные возможности скорее усложняют сопровождение и ведение проектов.
Для небольших проектов это не столь существенная проблема. Но с ростом проекта эти моменты выходят на первый план. А лучшие практики пока просто не сумели настояться и стать повсеместными - Rust достаточно молодой язык.
Но реальность использования такова, что без общепринятых и устоявшихся практик, эти мощные возможности скорее усложняют сопровождение и ведение проектов.
Всё-таки спорно. Без макросов пришлось бы писать больше бойлерплейта, причём как автору библиотеки, так и пользователю. Не всегда однозначно, что лучше: лаконичный, но более сложный код или более простой, но объёмный.
Я не против макросов так таковых.
Я за разумное применение макросов - чтобы это не добавляло сложности в первую очередь и было удобно во вторую. Такая очередность просто потому, в профессии программиста, изучать и поддерживать существующий код приходится гораздо чаще, чем писать новый.
И современное использование макросов (особенно на примере смарт-контрактов под разные платформы) явно выходят за рамки удобного.
Определенные проблемы в бойлерплейте есть, но кодогенерация их значительно снимает в большинстве случаев.
Впрочем, макросы подобной кодогенерацией, как правило, и занимаются. Я скорее за развитие кодогенерации в целом как независимого инструмента, а не вот этой "магии" макросов, которая может значительно поднять кривую изучения (пускай и не всегда).
Не всегда однозначно, что лучше: лаконичный, но более сложный код или более простой, но объёмный.
Лично я однозначно выбираю простой код. Просто потому что сопровождение такого кода проще и менее подвержено ошибкам.
Дайте угадаю. Вы, судя по почерку, сейчас описываете какой-то проект на фреймворке Substrate? Если да, то я вам сочувствую, бегите если можете, пока ещё не поздно. Но весь остальной Раст — он не такой. Просто Substrate — это очень overengineered экосистема, и если вы начали свой путь в Расте с неё — то ничего удивительного нет, что вас это отпугнуло.
Кто не в теме — Substrate это платформа для создания блокчейнов. Блокчейн Pokadot написан с использованием этой платформы (а если совсем точно — то этот фреймворк родился в результате эволюции польки, отделился как самостоятельный проект).
Но, повторюсь, это экстремальный пример. Остальной Раст — он прекрасен.
На мой, взгляд, этим страдает не только Substrate, а все платформы смарт-контрактов на WASM. Пару лет назад специально изучал платформы с контрактами на WebAssembly - именно такое впечатление сложилось.
Разве что wasmd (CosmWasm) мне показался достаточно адекватным (если не брать их Sylvia framework, благо что он опционален).
Выше писал, что по факту мои претензии к Rust скорее связаны с выводом типов и с неочевидностью ошибок, которые этот вывод порождает. Да, в большинстве случаев Rust генерит очень подробные описания ошибок. Да, у Rust в большинстве случаев прекрасная документация. Но на мой взгляд, этого не хватает. Зачастую очень сложно понять, что именно компилятору не нравится в твоем коде, в отличие от других языков (например, Java/Golang), где из скудных описаний хотя бы сразу понятно куда смотреть и что делать (в большинстве случаев, сложные проблемы тоже бывают, но гораздо реже).
С макросами аналогично - очень часто с ними всплывают труднопонимаемые ошибки. Кроме того, макросы очень сильно усложняют чтение и понимание исходного кода используемых библиотек.
Свое очарование у Rust-а есть, с этим сложно спорить. Но сложные для понимания ошибки оставляют не лучшее впечатление. Сюда же накладывается быстрое развитие экосистемы - обновления зависимостей часто порождают дополнительные ошибки. Причем я не могу сказать, что ошибки сложно исправлять - если понял в чем именно ошибка, то исправление в большинстве случаев достаточно тривиальное.
Именно поэтому я и говорю, что впечатление смешанное. Чем Rust хорош - об этом написано много статей. Но у него есть и проблемы - про это тоже не надо забывать.
P.S. часть про макросы писал под впечатлением скорее Sylvia framework, недавно его изучил для расширения кругозора. Впечатление, откровенно говоря, осталось очень не очень. Но опять же - спасибо, что он опционален.
Зачастую очень сложно понять, что именно компилятору не нравится в твоем коде, в отличие от других языков (например, Java/Golang), где из скудных описаний хотя бы сразу понятно куда смотреть и что делать
У меня ощущение (переходящее в уверенность), что это сильно зависит от навороченности предлагаемых языком инструментов/абстракций. Если писать можно только "тупой" код, то читать и отлаживать его, на первый взгляд, проще. С другой стороны, в низкоуровневных деталях может теряться идея. Банальный пример: цепочку skip(...).map(...).filter(...).collect(...)
легко окинуть взглядом, а в циклы надо вникать дольше. Писать такой после некоторого периода привыкания тоже проще. Что лучше спорить не буду, но свой выбор я сделал.
Конкретно с растом ситуация ещё усложняется низкоуровневостью. В языках со сборкой мусора не нужен бороу чекер. Можно и с другой стороны зайти, опять через упрощение — убираем попытки гарантировать всякое статически и пишем на С. Компилятор бьёт по рукам куда меньше, но шанс взрыва в рантайме больше.
Раст — это набор компромиссов и его недостатки — продолжение достоинств.
Кстати, о джаве. Я не специалист по этому языку, но ведь там можно обмазываться аннотациями не хуже, чем макросами в расте?.. Говорю про штуки вроде Lombok. Как там с ошибками и очевидностью?
У меня ощущение (переходящее в уверенность), что это сильно зависит от навороченности предлагаемых языком инструментов/абстракций.
Полностью согласен. Большие возможности языка налагают больше ответственности на разработчика. Если что-то можно написать "не так" - то это напишут "не так".
Впрочем, ту вопрос даже не навороченности языковых конструкций, а вопрос гибкости и возможностей языка в целом. Взять тот же JavaScript. На вскидку - очень простой язык. Но очень и очень гибкий (на вскидку - самый гибкий из известных мне). И вот это сочетание простоты и гибкости, на мой взгляд, не идут JavaScript-у на пользу. Или взять Golang. Простой язык (пусть и сложнее JS-а, на мой взгляд), но и особой гибкости нет. В результате - и говнокода сильно меньше.
Rust именно что навороченный язык. И я тоже не могу сказать, что это идет ему на пользу. Впрочем, открытым остается и вопрос - а мог ли Rust обойтись без этой навороченности? А стал бы он тогда так популярен? Так что тут палка о двух концах.
И вопрос не в тупости кода, а в его поддерживаемости. Тот же skip(...).map(...).filter(...).collect(...)
вполне и на Java работает и активно используется (как и во многих других языках), причем синтаксис будет точно такой же. В простых сценариях простая копи-паста такого кода из Rust в Java потребует минимальных правок. Так что это не уникальная фишка Rust-а.
Уникальная фишка Rust-а, на мой взгляд, это концепция владения переменной (и ее последствия - вроде указания времени жизни ссылок и т.д.). Что позволяет иметь GC по факту без GC. Что сильно повышает скорость работы работы и предсказуемость времени выполнения алгоритма (GC не вмешивается в работу). А минимальный рантайм и компилируемость в выполняемый бинарник позволяет говорить о Rust-е как о низкоуровневом языке. Впрочем, не стоит забывать, что низкоуровневость - это не случайный результат (побочная фишка языка), а результат серьезного труда на попадание в эту нишу. Сам по себе язык очень высокоуровневый.
А практически все остальное - так или иначе есть и в других языках.
Кстати, о джаве. Я не специалист по этому языку, но ведь там можно обмазываться аннотациями не хуже, чем макросами в расте?.. Говорю про штуки вроде Lombok. Как там с ошибками и очевидностью?
Есть, но я и в Java не любитель подобных штук. В Java кодогенерация встраивается как часть процесса компиляции, что тоже требует определенных костылей. А в целом аннотации - это просто метки у методов/классов, они ни на что не влияют (если явно не учитывать и не анализировать эти метки в рантайме или при компиляции).
Впрочем, в Java такие вещи крайне редко встречаются, в отличие от Rust-а, где кодогенерация повсеместна (я про кодогенерацию, а аннотации очень часто используются в Java, причем в рантайме, что не идет на пользу скорости выполнения Java).
Я согласен, что кодогенерация - штука очень мощная и полезная, к этому вопросов нет. Другое дело, что нет устоявшихся правил и подходов к кодогенерации. А главное - явных ограничений, чтобы эти правила и подходы были прописаны на уровне языка. Это приводит зачастую к очень сложному коду, что для чтения, что для написания, что для понимания. Впрочем, Rust, как один из первопроходцев в этом вопросе, вполне ожидаемо, что имеет некоторые проблемы в этом (может Rust и не первый, но я не помню других популярных языков с повсеместной кодогенерацией).
Си - тоже очень гибкий язык, я бы даже сказал излишне гибкий. Но Си появился очень и очень давно и дал начало целому классу языков. И сейчас практически все языки Си-подобные (включая Rust).
Так и с кодогенерацией - ее рассвет, на мой взгляд, еще впереди. И Rust послужит серьезной вехой в этом пути.
Rust именно что навороченный язык. И я тоже не могу сказать, что это идет ему на пользу.
По всей видимости, я предпочитаю именно "навороченные" языки.
Тут забавная ситуация: не так уж редко слышно мнение в дуже "хочу раст, но более простой". Вплоть до того, что люди хотят раст со сборкой мусора просто из-за удобств вроде паттерн матчинга, карго и т.д. Меня это несколько удивляет.
И вопрос не в тупости кода, а в его поддерживаемости. Тот же skip(...).map(...).filter(...).collect(...) вполне и на Java работает и активно используется (как и во многих других языках), причем синтаксис будет точно такой же. В простых сценариях простая копи-паста такого кода из Rust в Java потребует минимальных правок. Так что это не уникальная фишка Rust-а.
Так я про уникальность ничего и не говорил. Это просто первый пример сравнения (более) высокоуровневой абстракции и "низкоуровневого" (не системного, а именно перегруженного мелкими деталями), который пришёл в голову. Есть люди, которые не хотят (в С++) ничего слышать про ренджи, а то и про итераторы, предпочитая "более простой" код с циклами и указателями, но это именно нежелание учиться. Это аргумент, что "тупой" код совсем не обязательно проще читать, писать и модифицировать, но разработчику для этого придётся прочитать что-то большее, чем пару страниц про язык.
А практически все остальное — так или иначе есть и в других языках.
Пусть так, хотя я считаю явное выделение unsafe части тоже очень важным. А вот если говорить не о просто "фича есть в каком-то языке", а "такой набор фич в одном системном языке", то выбор сильно сужается.
Тут забавная ситуация: не так уж редко слышно мнение в дуже "хочу раст, но более простой". Вплоть до того, что люди хотят раст со сборкой мусора просто из-за удобств вроде паттерн матчинга, карго и т.д. Меня это несколько удивляет.
Да, в Rust на многие вещи взглянули очень свежим взглядом. И те же enum-ы, которые в других языках, в большинстве своем, считались чуть ли не устаревшими конструкциями, заиграли новыми красками.
И да, рано или поздно этот набор фич разойдется по новым языкам и появится в существующих языках. Пускай не так быстро, как того хотелось бы, но это произойдет.
Это аргумент, что "тупой" код совсем не обязательно проще читать, писать и модифицировать, но разработчику для этого придётся прочитать что-то большее, чем пару страниц про язык.
Я никогда не топил за "тупой" код. Я топлю за читаемость кода. За легко-понимаемый код. Чтобы взглянул и сразу понял, что именно тут творится и как именно это работает. И у Rust-а, на мой взгляд, именно с читаемостью кода есть проблемы. В части "что именно творится" мешают макросы, а в части "как именно это работает" мешает вывод типов. Да, это очень гибкие и мощные инструменты. Но их гибкость и мешает пониманию кода.
То, что код на Rust выглядит достаточно просто (и компактно), не делает его легким для понимания. Да, с опытом и практикой, код станет легче читать и понимать. Но это никогда не станет достаточно простым делом, особенно при знакомстве с новым проектом.
Причем писать код на Rust зачастую даже легче, чем вникать в существующий код. А если его еще и дорабатывать надо... И это серьезный недостаток, на мой взгляд.
Но опять же - это все ИМХО "с моей колокольни", а моя колокольня - это Java/Golang, а не C/C++. С точки зрения разработчика C/C++, Rust может выглядеть совсем по другому.
Я никогда не топил за "тупой" код. Я топлю за читаемость кода. За легко-понимаемый код. Чтобы взглянул и сразу понял, что именно тут творится и как именно это работает.
Мне кажется, что одно часто подменяют другим. Просто "топлю за простой-дубовый код" звучит не очень. Скажем, хаскель мне достаточно интересен и симпатичен, но я его толком не знаю. Пару раз читал книги, но без практики это всё быстро забывается. Так вот, сторонники этого языка рассказывают какой он высокоуровневый и как монады помогают писать лаконичный код. Но если взять обычного сишника или джависта, то "взглянул и сразу понял" и близко не будет. И в рамках этого языка тоже есть продвинутые штуки для которых нужно ещё более углубленное знакомство. Считаю, что с растовыми макросами примерно так же. Если они хорошо написаны, то достаточно прочитать пару абзацев доки и становится понятно.
А запутанный код можно писать и городя упоротые иерархии наследования и даже в процедурном стиле. Думаю мы оба согласны с тем, что больше гибкости — больше возможных проблем. Просто я считаю, что преимущества перевешивают эти потенциальные проблемы.
Скажем, хаскель мне достаточно интересен и симпатичен, но я его толком не знаю.
Хаскель помимо активной практики требует и определенного, как бы сказать, состояния разума. И мне удалось это состояние поймать во время обучения в универе. Но это было уже очень давно и текущего опыт разработки у меня еще не было, чтобы адекватно оценить этот опыт. Общее впечатление - да, мне понравилось, было очень интересно. Но понимание хаскеля быстро ушло - сказалось отсутствие практики.
Но если взять обычного сишника или джависта, то "взглянул и сразу понял" и близко не будет. И в рамках этого языка тоже есть продвинутые штуки для которых нужно ещё более углубленное знакомство.
Тут больший вопрос, что это принципиально разные парадигмы программирования. Языки чисто функционального программирования и языки с элементами функционального программирования - это очень большая разница просто в подходах к программированию.
А запутанный код можно писать и городя упоротые иерархии наследования и даже в процедурном стиле.
Запутанный код - это результат в первую очередь истории развития кода и навыков разработчика. Никогда не видел, чтобы специально писали запутанный код. Влияние именно языка тут достаточно вторично.
Думаю мы оба согласны с тем, что больше гибкости — больше возможных проблем. Просто я считаю, что преимущества перевешивают эти потенциальные проблемы.
Да, больше гибкости - больше проблем, с этим сложно спорить. Но тут вопрос не только в гибкости, но и в сложности языка. Есть очень гибкий язык - JavaScript. Но это при этом очень простой язык.
В части Rust преимущества может и перевешивают потенциальные проблемы. Но тут главный вопрос - для кого перевешивают?
Для опытного разработчика - да, перевешивают.
Для начинающего разработчика - нет.
Для соло-разработки - да, возможно.
Для командной разработки - сомневаюсь.
Для небольших проектов - да, перевешивают. Вообще, возможность "быстро переписать если что", может оправдать практически любые эксперименты.
Для больших проектов - опять же сомневаюсь, что перевешивают.
А если учесть, что опыт/размер команды/размер проекта - это независимые и недетерминированные факторы, то получаем трехмерное пространство оценки...
Так что опытному разработчику на небольшом проекте в соло - Rust вполне подойдет.
А команде начинающих разработчиков да на большом проекте - лучше выбрать тот же Golang.
А во всех остальных случаях есть нюансы...
Тут больший вопрос, что это принципиально разные парадигмы программирования.
Согласен, но это просто утрированный пример. Помню жаркие споры и насчёт auto и рейнджей в С++. И аргументы обычно такие же: код сложнее читать/писать, хотя новой парадигмой там и не пахнет.
Запутанный код — это результат в первую очередь истории развития кода и навыков разработчика. Никогда не видел, чтобы специально писали запутанный код. Влияние именно языка тут достаточно вторично.
По моему, мы уже N комментариев только и говорим, что о том как влияет навороченность языка на (не)очевидность кода. (:
Есть очень гибкий язык — JavaScript. Но это при этом очень простой язык.
Выше не стал спорить с этим утверждением, а вот сейчас не удержусь: мне JavaScript простым не кажется. Хотя в целом динамически типизированные языки не люблю — без типов мне сложно читать код. Опять же, неявных правил много. Да, на первый взгляд — всё как-то работает, но не считаю это простым.
Для небольших проектов — да, перевешивают. Вообще, возможность "быстро переписать если что", может оправдать практически любые эксперименты.
Для "быстро написать/переписать" раст уж точно не лучший выбор.
Для больших проектов — опять же сомневаюсь, что перевешивают.
А я наоборот считаю, что чем больше проект, тем важнее становятся инструменты абстрагирования и сильная/навороченная типизация.
Вот сложность нанять, скажем 100 более-менее опытных раст-разработчиков уже влияет в другую сторону.
По моему, мы уже N комментариев только и говорим, что о том как влияет навороченность языка на (не)очевидность кода. (:
Я тут имел в виду, что запутанный код - явление есть везде и всегда как фактор развития кодовой базы проекта. И язык, в идеале, своими конструкциями, не должен добавлять дополнительных сложностей в читаемость кода.
Выше не стал спорить с этим утверждением, а вот сейчас не удержусь: мне JavaScript простым не кажется.
Именно основы языка, его концепции очень простые (и, на удивление, лаконичные). Немного сложностей в плане ООП, но это все из серии "изучить нюансы и запомнить".
Лично мне в JS не нравится два фактора:
Динамическиая типизация - плохо работает IDE, много ошибок всплывает в рантайме (впрочем, тут спасет TypeScript).
Но TypeScript - это скорее C#, от JavaScript осталось очень мало.
Инфраструктура. Все очень быстро меняется, много кода низкого качества и сама по себе инфраструктура стала очень самобытной (тут TypeScript уже не спасает). Для изучения/погружения требуется очень много времени и сил, а знания очень быстро устаревают.
Для "быстро написать/переписать" раст уж точно не лучший выбор.
Если цель - написать сервис, то лучше привычные инструменты использовать, тут вопросов нет. А если цель - изучить Rust (и оценить его пригодность для других проектов), то вполне рабочий подход. Правда времени займет много (что на изучение Rust, что на использование в первое время).
А я наоборот считаю, что чем больше проект, тем важнее становятся инструменты абстрагирования и сильная/навороченная типизация.
В больших проектах, в больших командах - очень важен фактор читаемости кода. Если все в команде "собаку съели на Rust" - то это один вопрос. Впрочем, опять же, от проекта сильно зависит. Если для веб-сервиса выбор Rust - достаточно специфичный случай (потому как много альтернатив), то для написания прошивки выбор уже не столь неоднозначный (потому как безопасность решает).
И другой фактор, который лично мне не дает рекомендовать Rust для больших проектов - фактор поддерживаемости инфраструктуры. Rust сейчас очень быстро развивается. А это означает, что часто будут возникать проблемы с обновлением зависимостей (а для исправления нужно очень много трудозатрат). Или код сразу после написания будет устаревшим из-за использования устаревших либ (и устаревшей редакции языка).
В больших проектах, в больших командах — очень важен фактор читаемости кода. Если все в команде "собаку съели на Rust" — то это один вопрос.
Пожалуй, в последний раз скажу, что не вижу каких-то особых проблем у раста в этом плане. Да, у языков разный порог входа, на С++, расте, скале и т.д. не получится набрать одних новичков, дать им прочитать пару страниц мануала и посадить писать код.
фактор поддерживаемости инфраструктуры. Rust сейчас очень быстро развивается.
А по моему сейчас уже всё достаточно устаканилось. Можно утверждать, что в 90% случаев используется токио и зоопарка асинхронных рантаймов нет. Два года с релиза 1.0 библиотека обходится без ломающих изменений. Серде — стандарт сериализации, если не нужно что-то прям особенное, 6 лет как выпускают только патчи. С обработкой ошибок тоже уже года три как пришли к сложившимся практикам. Логирование — хотел сказать, что tracing
появился недавно, но посмотрел — четыре года уже прошло. Но до этого был log
(обычно в связке с env_logger
), так вот трейсинг совместим с этими библиотеками. То есть, это просто эволюция без слома всего.
Хотя всё относительно, конечно. Но раньше было куда "веселее".
и устаревшей редакции языка
Справедливости ради, изменения в редакциях пока что были скорее косметическими. Импорт макросов и изменения в юзингах хоть и могут много шума (дифф) создавать, но изменения там чисто механические. Уже не помню, но возможно тулза для миграции даже автоматически это может исправлять.
Пусть так, хотя я считаю явное выделение unsafe части тоже очень важным. А вот если говорить не о просто "фича есть в каком-то языке", а "такой набор фич в одном системном языке", то выбор сильно сужается.
Системных языков в целом не так уж и много. И безопасность кода (включая UB) - это типичная проблема именно C/C++, а не Java/C#.
Но да, в части системных языков, Rust - это серьезная альтернатива C/C++.
Системных языков в целом не так уж и много.
Ага, но заменять условную джаву растом достаточно странно. В каких-то случаях это может быть оправданно, но у языков всё-таки есть свои ниши и сформировавшаяся инфраструктура. Поэтому и сравнивать фичи языка в отрыве от их применения смысла мало. Толку мне от прекрасного языка, если использовать его всё равно не получится?..
Ну и, кстати, сейчас языков претендующих на системность стало побольше: Rust, Nim, Zig, C3, Odin. Наверняка, что-то забыл. Плюс D ещё подаёт признаки жизни.
.
Точно! Хотя мне карбон пока ещё кажется экспериментом, который могут и прикрыть, но посмотрим. Ещё можно вспомнить Verona от микрософт.
Да, искать замену Java в виде Rust - сомнительное занятие в общем случае (пускай частности и могут сыграть). Ниши сильно разные.
Хотя и не сказать, что эти ниши не пересекаются - например, в части написания микросервисов - что Rust, что Java (что куча других языков) чувствуют себя прекрасно.
И я сравниваю не фичи языков, а оцениваю Rust в целом из собственного опыта разработки ПО. И вижу определенные проблемы в Rust. Да, идеал недостижим - чем-то приходится жертвовать в любом случае, и к этому вопросов нет. Но из оценки достоинств и недостатков и строится правильный выбор технологии. И говорить только лишь о достоинствах Rust - не есть хорошо.
P.S. Вопрос сравнимости фич языков в отрыве от их области применения - тема, достойная отдельной дискуссии.
Не надо сравнивать с Питоном. Раст там близко не стоял, слишком высокий порог входа.
Нельзя просто так взять и начать писать на Раст в отличие от Питон.
Скорее всего он так и останется нишевым языком.
Скорее всего он так и останется нишевым языком.
Конечно, питон же самый лучший язык.
Нельзя просто так взять и начать писать на Раст в отличие от Питон.
Типа, можно взять первого попавшегося человека с нулевым опытом в программировании, посадим его за компьютер с установленным питоном, и он зафигачит нам какой-нибудь веб-магазин на джанге? Ага, конечно.
Скорее просто Rust не будут использовать как язык для обучения программированию и для написания маленьких простых программ. Но он и не претендует на эту нишу.
Вход в Rust действительно более крутой, чем во многие другие языки. Но зато дальше разобраться в нём становится проще, так как меньше неприятных нюансов и всякого заметённого под ковёр в других языках.
для написания маленьких простых программ.
Почему? Мне кажется подходит.
Вход в Rust действительно более крутой, чем во многие другие языки.
Вы меряете сложность входа с какого начального уровня знаний входящего?
Мы в качестве эксперимента попробовали обучать Rust'у 10-летних детей, имеющих до этого опыт только в Scratch. Результаты примерно такие же, как при обучении Python, с небольшой помощью пишут примитивные игры. Большая часть сложностей Rust - не сложность языка как такового, а сложность ломания привычек, наработанных в других языках.
нет. сразу "нет" этой статье. я отвечу с позиции раст-разработчика:
Он быстрый.
да. он быстрый. но в определенных сценариях оптимизация кода совершенно неочевидна.
Он безопасный.
да. если вы пишете обычную либу в обычных условиях. так это и в других языках так.
а если вы пишете низкоуровневую библиотеку, где вы можете четко оперировать адресами памяти - вот тут раст может создать препятствия.
Он необычный.
да. когда вы работаете в концепте написания обычного приложения - столкнетесь с отличной штукой - временем жизни переменной.
в остальном - не. я писал на десятках языков, раст - просто изумителен. но - язык.
Он отлично документирован
кстати, поправьте в оригинальной статье "от отлично..".
да!!!!!!! офигенная документация. но... тяга к документированию всего вносит свои коррективы. я очень хочу написать статью про вред инлайн-документации для разработки по. может, я и не прав.
все остальное... знаете, раст не решит ваших проблем, если Вы - хреновый программист. не решит проблем когда решите, что O(n) алгоритм на раст быстрее O(log n) алгоритма на javascript в случае веба. раст - хороший язык, когда вы знаете, что хотите. как в си, например. но - раст. и я очень люблю этот язык.
дополнения к своему комментарию. я люблю раст и расцениваю его как основной язык разработки. моя имплементация сравнений строк в бд на расте - я собираюсь писать об этом серию статей про сопоставления (collation) в базах данных, сравнениях. в бенчах я превзошел icu4x, и думаю что это интересно для хайлоада, например.
работа на низком уровне с памятью - тоже unsafe часть раста, который, с одной стороны, хочет занять нишу высокоуровневого языка с доступом к памяти, с другой стороны - низкоуровневого. тоже момент, который прямо требует статьи
Хех, надеюсь хайп, который уже начинается не приведет к отвращению тех - кто уже давно тут.
Как по мне Rust обычный пример Скорость/Качество, мы жертвуем скоростью разработки, но в отличии от С он более дружелюбный к новичкам. Экосистема где всё есть, но не является частью самого языка; я рад что ноунеймов отпугнуло недавнее событие с приватизацией товарных знаков.
Любите ли вы Rust, как люблю его я?