Сначала я просто собирался написать комментарий к моему предыдущему тексту, в котором я рассказал, как за день на расте мне удалось написать новую, неспецифицированную, глючную и медленную реализацию половины 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")], не пытались превратиться в доктесты и не ломали сборку (какие ещё доктесты в отвлеченных текстах, алё).
Еще раз повторю, что язык мне в общем и целом понравился. Скорее всего, среди претензий выше многие вызваны моим невежеством — если так, буду благодарен за подсказки в комментариях. Писать «раст — лучший, автор — тупой, здесь так принято» — в комментариях большого смысла не имеет, автор в курсе.
