Сначала я просто собирался написать комментарий к моему предыдущему тексту, в котором я рассказал, как за день на расте мне удалось написать новую, неспецифицированную, глючную и медленную реализацию половины OTP.
Но пока я тот комментарий писал, внезапно оказалось, что, несмотря на общее положительное впечатление от раста, претензий к нему у меня набралось на целый текст. Ну что ж, заточите свои минусаторы, ниже — мой неполный и очень предвзятый список претензий к расту.
Документация
▸ прицепить текст на маркдауне к документации — фактически невозможно, есть костыли типа https://github.com/Geal/cargo-external-doc и директива #![doc = include_str!("path/to/file.md")], которая всё портит (и бибикает).
Как надо: в Cargo.toml должен быть список файлов, которые я хочу превратить в отдельные страницы документации (видимые в левом меню на https://docs.rs)
Строки
▸ интерполяцию строк писал какой-то герпетолог, ей-богу (или сиквелянт); неужели целесообразно заставлять читателя индексировать набор параметров глазами: "{} + {} = {}", a, b, c?
Как надо: "{a} + {b} + {c}"
Паттерн-матчинг
▸ матчи внутри одной функции вместо нескольких голов, компилируемых во внутренний матч — ну чуваки, вы вообще хоть одну завалящую статейку про «как оно сделано у соседей» читали, или сразу свой велосипед строить начали?
fn handle_event(event: Self::Event, state: Self::State) -> StateTransition<Self> {
match (state, event) {
(DoorState::Locked, DoorEvent::Button(digit)) => { … }
(DoorState::Open, DoorEvent::Lock) => { … }
_ => StateTransition::keep_state(Err("Invalid event".into())),
}
}
Как надо:
fn handle_event(event: Self::Event, state: Self::State) -> StateTransition<Self>
fn handle_event(DoorState::Locked, DoorEvent::Button(digit)) { … }
fn handle_event(DoorState::Open, DoorEvent::Lock)) { … }
fn handle_event(_, _) { StateTransition::keep_state(Err("Invalid event".into())) {}
Да и вообще, паттерн-матчинг после эрланговского выглядит убогим, я даже в Cure уже успел что-то подобное, но я не буду заявлять о готовности к продакшену, пока не реализую полную декомпозицию от x = 1; 1 = x до {foo: {bar: value, baz: 42}} when value > 42 = struct. И вообще, хорошо бы иметь свой оператор для матча, как = в эрланге.
Ссылки
▸ почему ссылки &foo — не поведение по умолчанию?! Особенно учитывая, что в качестве аргумента функции для модификаций (мутабельно) можно передать только ссылку &mut foo? Ну ё-моё, сделайте всё ссылками и специально заставьте крохоборов вызывать оператор копирования если нужно что-то передавать по значению (в 2025 году это нужно трём с половиной людям, которые все равно предпочтут расту — ассемблер). А ведь есть еще и «умные указатели»!
Как надо: самый простой вариант — по умолчанию всё ссылка; если нужен доступ по значению — его надо указывать эксплицитно: fn foo(mut self, val event: …).
Метапрограммирование
Это ад. Всё, кроме этого — вкусовщина и вопрос привычки, но если в языке в 2025 году заявлено метапрограммирование — оно не может быть настолько убогим.
▸ метапрограммирование накостылено сбоку (что является, конечно, следствием отсутствия прямого доступа к AST). Какие-то метапеременные, пять разных типов макросов, нечитаемый синтаксис (код на расте в принципе легко проглатывается с листа даже теми, кто видит его впервые; первый же пример макроса в документации выглядит вот так: macro_rules! ambiguity { ($($i:ident)* $j:ident) => { }; }. Единственная возможная реакция человека, столкнувшегося с этим перлом, — WTF? Вы издеваетесь, что ли? Почему нельзя было сделать по-человечески? Что с unquote — тоже неясно. В каком-то смысле #var отвечает за это, но я, даже реализовав свой макроатрибут, так до конца и не понял, как работает механизм quote/unquote.
▸ с какого-то хрена для макросов нужен отдельный крейт, такого гигантского WTF я со времен изучения настройки новелловской сети не помню.
Как надо: как в эликсире (на худой случай — как в эрланге). Язык компилируемый, два прохода, гигиена и ультимативный эксплицитный unquote, в котором может быть практически любой код, а не то, что проглотит #….
Тесты
▸ какие тесты я кладу рядом с кодом, какие в папку test?
▸ как в доктестах инициализировать контекст?
▸ как просто найти все доктесты в файле глазами?
▸ как запускать часть тестов асинхронно?
Как надо: если не пропадёт запал, следующим шагом портирую mox и nimble_ownership.
Комментарии
▸ комментарии — это ад; 2025 год на дворе, но я не могу просто прочитать документацию перед функцией, нет — передо мной выстроен частокол //!. Ну как так-то?
Как надо: да как угодно, но только, чтобы в текст комментария не вторгались управляющие символы, не имеющие к нему никакого отношения. И чтобы блоки кода из документационных файлов, вставленных директивой #![doc = include_str!("path/to/file.md")], не пытались превратиться в доктесты и не ломали сборку (какие ещё доктесты в отвлеченных текстах, алё).
Еще раз повторю, что язык мне в общем и целом понравился. Скорее всего, среди претензий выше многие вызваны моим невежеством — если так, буду благодарен за подсказки в комментариях. Писать «раст — лучший, автор — тупой, здесь так принято» — в комментариях большого смысла не имеет, автор в курсе.
Комментарии (13)

BeardedBeaver
06.12.2025 10:40Как надо:
"{a} + {b} + {c}"
cupraer Автор
06.12.2025 10:40Ок, я даже почитал комментарии в ветке с реквестом на гитхабе. Это работает только для локальных переменных, запихнуть туда копипастой параметр не удастся (см. мой комментарий с ошибкой выше). Это уже не WTF, это просто позорище.

codecity
06.12.2025 10:40Почти все недовольны макросами.

cupraer Автор
06.12.2025 10:40«Почти все» из какой именно выборки? Какие проекты? Какие страны?
Кроме того, я не «недоволен» же, я просто вижу, как можно было бы лучше, если бы AST не прикручивали сбоку, но сейчас уже поезд ушел.

Dhwtj
06.12.2025 10:40
Всё прогнило AST
"Код = данные" это уязвимость. В Lisp (eval (read)) — прямой путь к code injection. Хотя, если только compile time... Ну, ок, соглашусь.

Dhwtj
06.12.2025 10:40Токио асинк тоже макрос
#[tokio::main] async fn main() { foo().await; } // Развернётся примерно в: fn main() { tokio::runtime::Runtime::new() .unwrap() .block_on(async { foo().await; }) }Все довольны.

cupraer Автор
06.12.2025 10:40Коллега говорил про разработчиков. В случае токио надо спрашивать разработчика токио.
Моим
gen_statemтоже удобно пользоваться. Но он выпил тонну моей крови, пока я его написал.#[gen_statem(fsm = r#" [*] --> locked locked --> |coin| unlocked locked --> |push| locked unlocked --> |push| locked unlocked --> |coin| unlocked unlocked --> |off| [*] "#)]
Dhwtj
3 года уже как можно
Можно самому написать макрос
cupraer Автор
О как. Спасибо.Да ну? Я вот попробовал, есличё.
Dhwtj
Не знаю, как ссылку дать туда
Вычисление в {}?
Может и не сработает. ХЗ
cupraer Автор
Никак не привыкну, что советы тут дают одни диванные теоретики.
cupraer Автор
Да можно и весь язык самому написать, я так и сделал недавно. В комментариях к данному тексту мы обсуждаем другой, уже написанный язык.