История изменений
Исправление hateyoufeel, (текущая версия) :
Расскажите пожалуйста. Интересно.
Поехали.
Сам язык:
- Отсутствие Higher-Kinded Types. Растовики оправдываются, мол, это сложно блаблабла, но если это есть во всех языках, из которых Rust черпал идеи, включая C++, то я что-то не верю.
- Жёсткий запрет на Orphaned Instances. В Haskell это является предупреждением компилятора и этого стоит избегать, а в Rust просто запретили и всё. В результате, если у тебя
trait
объявлен в одном пакете, а структура или тип в другом, ты никак не можешь сделать нормально impl этого трейта без создания зависимости между двумя пакетами. Поэтому почти все крейты зависят от serde и подобных, хотя этого не слишком-то нужно. - Просто чудовищная срань с async. Атрибут async является «заразным» для функций, т.е. если ты хочешь вызвать async функцию, весь стек вызовов до самого main включительно должен быть async. Из-за этого у некоторых библиотек есть два варианта: одна async, другая нет.
- Чудовищная срань с async #2: использование async тянет достаточно жирный рантайм и далеко не всегда ведёт к улучшению производительности. Часто наоборот, async код становится только тормознее из-за вагона блокировок под капотом.
- Срань вокруг async #3: Unpin и вот это вот всё. Просто чудовищный костыль.
- Необходимость постоянного рефакторинга, иногда в случае малейших изменений. Растокрабы любят бить себя членом в лоб, рассказывая про безопасность рефакторинга из-за мощной системы типов (всё так), но забывают сказать, что этого рефакторинга выходит больше чем в других языках. Хороший пост по теме: https://loglog.games/blog/leaving-rust-gamedev/
- Вездесущий вызов
.unwrap()
. Rust по идее заставляет проверять возвращаемые значения через типыOption
иResult
, но толпы говнокодеров просто лепят.unwrap()
в код, который в случае негативного значения (None, Error, etc) тупо дёргаетpanic!()
. Это можно было бы решить монадами, но в Rust нельзя написать нормальные монады из-за отсутствия HKT. Поэтому иногда какая-нибудь библиотечка может при несовпадении инвариантов убить твою прогу и высрать стектрейс в консоль, а тебе потом разбираться.
Тулинг:
- Rustc тормозной. Я иногда на GHC ругаюсь, но скорость сборки кода на Rust может поражать. В плохом смысле. Можешь как-нибудь на досуге собрать Firefox и оценить, сколько занимает сборка плюсовой части и сколько занимает Rust. Особенно страдает тут код с макросами (у плюсов эта проблема тоже есть, попробуй скомпилить любой код, использующий Boost::Karma/Spirit).
- Выжрать вагон памяти при сборке – ваще не вопрос.
- Гигантские бинарники. Про это уже все отписались. Если на место на диске в принципе плевать, то на скорость уже не настолько. Частью проблемы тут является пункт #2 выше про orphaned instances, из-за которых всё линкуется со всем. Проблема не распространяется на embedded и ядро, к слову. Это чисто юзерспейный задвиг.
Список далеко не полон, но это самые больные для меня вещи, пришедшие в голову с утреца пораньше. Rust получился гораздо хуже чем мог бы. Но при этом это всё равно лучше чем то что делает 95% говнокодеров на Си.
Исходная версия hateyoufeel, :
Расскажите пожалуйста. Интересно.
Поехали.
Сам язык:
- Отсутствие Higher-Kinded Types. Растовики оправдываются, мол, это сложно блаблабла, но если это есть во всех языках, из которых Rust черпал идеи, включая C++, то я что-то не верю.
- Жёсткий запрет на Orphaned Instances. В Haskell это является предупреждением компилятора и этого стоит избегать, а в Rust просто запретили и всё. В результате, если у тебя
trait
объявлен в одном пакете, а структура или тип в другом, ты никак не можешь сделать нормально impl этого трейта без создания зависимости между двумя пакетами. Поэтому почти все крейты зависят от serde и подобных, хотя этого не слишком-то нужно. - Просто чудовищная срань с async. Атрибут async является «заразным» для функций, т.е. если ты хочешь вызвать async функцию, весь стек вызовов до самого main включительно должен быть async. Из-за этого у некоторых библиотек есть два варианта: одна async, другая нет.
- Чудовищная срань с async #2: использование async тянет достаточно жирный рантайм и далеко не всегда ведёт к улучшению производительности. Часто наоборот, async код становится только тормознее из-за вагона блокировок под капотом.
- Срань вокруг async #3: Unpin и вот это вот всё. Просто чудовищный костыль.
- Необходимость постоянного рефакторинга, иногда в случае малейших изменений. Растокрабы любят бить себя членом в лоб, рассказывая про безопасность рефакторинга из-за мощной системы типов (всё так), но забывают сказать, что этого рефакторинга выходит больше чем в других языках. Хороший пост по теме: https://loglog.games/blog/leaving-rust-gamedev/
- Вездесущий вызов
.unwrap()
. Rust по идее заставляет проверять возвращаемые значения через типыOption
иResult
, но толпы говнокодеров просто лепят.unwrap()
в код, который в случае негативного значения (None, Error, etc) тупо дёргаетpanic!()
. Это можно было бы решить монадами, но в Rust нельзя написать нормальные монады из-за отсутствия HKT. Поэтому иногда какая-нибудь библиотечка может при несовпадении инвариантов убить твою прогу и высрать стектрейс в консоль, а тебе потом разбираться.
Тулинг:
- Rustc тормозной. Я иногда на GHC ругаюсь, но скорость сборки кода на Rust может поражать. В плохом смысле. Можешь как-нибудь на досуге собрать Firefox и оценить, сколько занимает сборка плюсовой части и сколько занимает Rust. Особенно страдает тут код с макросами (у плюсов эта проблема тоже есть, попробуй скомпилить любой код, использующий Boost::Karma/Spirit).
- Выжрать вагон памяти при сборке – ваще не вопрос.
- Гигантские бинарники. Про это уже все отписались. Если на место на диске в принципе плевать, то на скорость уже не настолько. Частью проблемы тут является пункт #2 выше про orphaned instances, из-за которых всё линкуется со всем.
Список далеко не полон, но это самые больные для меня вещи, пришедшие в голову с утреца пораньше. Rust получился гораздо хуже чем мог бы. Но при этом это всё равно лучше чем то что делает 95% говнокодеров на Си.