У меня, как наверное и у многих других C++ разработчиков какие-то сложные отношения с Rust. Этот язык вроде как и очень сильно нравится и в то же время всё сложно. На сей раз моя попытка заняться Rust в серьез зашла куда дальше чем обычно (обычно я после нескольких небольших тестиков удовлетворенно забрасывал изучение) – я нашел компанию которой нужны Rust разработчики, связался с ними и взял тестовое задание. Тестовое задание просто восхитительное, не сложное, но помогает понять главное – хочешь ли ты связываться с языком или нет?
На тестовое задание я честно потратил часов 8 и за это время успел заглянуть в tokio, которая, как я понимаю, является образцово-показательной библиотекой для написания асинхронных сетевых приложений. Честно говоря, я до сих пор в состоянии смятении, но точно знаю одно – видеть такое и не дай бог поддерживать на постоянной основе я точно не хочу. К примеру, вот кусок кода, который читает данные из канала и шлет их по TCP:
let (sink, stream) = stream.framed(Bytes).split();
pool.execute(stdin.forward(sink).then(|result| {
if let Err(e) = result {
panic!("failed to write to socket: {}", e)
}
Ok(())
})).unwrap();
stream
}).flatten_stream())
Несколькими месяцами раньше я баловался с биндингами к libClang, где было всё читабельно и очевидно, что наводит на мысли, что написать на Rust можно писать как в адекватном и легко поддерживаемом стиле, так и городить write-only код в духе приведенного выше. И надо отметить что в примере выше чувствуется и стиль и задумка. Если в него какое-то время повтыкать (желательно в IDE с навигацией, очень рекомендую IntelliJ Rust), то становится понятно что хотел сказать автор и почему. Только вот “НУ ЗАЧЕМ?!?!” не покидает.
В итоге мне в очередной раз стало казаться, что за пределами небольших сообществ гиков Rust взлететь не может, так как поддерживать столь неочевидные решения должно быть даже дороже чем решения на C++ с ручным управлением памятью (в конце концов, санитайзерами можно отловить практически всё). Не знаю чем это вызвано, скорей всего тем, что Rust развивает комьюнити гиков, а C++ комитет старперов. В результате в Rust тянут все, что круто выглядит, а в C++ только то, что “мегамозги” одобрили. Побочным эффектом этого выступает то, что в Rust многие удобные вещи доступны сразу или почти сразу, а в C++ это “наверное будет реализовано после C++20” (да-да, это я про Meta).
Наверное, меня всё равно не отпустит и баловаться с Rust я не перестану. Но вот подаваться на позицию “Rust разработчик” я довольно долгое время точно не буду, сообщество должно наиграться в “zero cost abstractions” для начала
А как выглядело задание, если не секрет)
Вариация на тему чата.
А что такого-то там в этом коде, не пойму?
Слишком большое количество разнородных действий в одной строке. Такое очень тяжело поддерживать.
>> можно писать как в адекватном и легко поддерживаемом стиле, так и городить write-only код в
духе приведенного выше
То ли дело на С++, там можно еще к этому парочку UB добавить, чтобы поддерживать было еще проще
>> так как поддерживать столь неочевидные решения должно быть даже дороже чем решения на C++ с ручным управлением памятью
Такое ощущение, что решения на С++ все сплошь очевидны. Какое-то странное сравнение.
>> в конце концов, санитайзерами можно отловить практически всё
До сих пор ловят. Почему-то не могут покрыть санитайзерами все 100% путей выполнения кода. Или проверять без сильной потери производительности и большого потребления памяти. Или одновременно запускать адресный с тредовым.
И уж точно ни в одной доке к санитайзерам нету секции Limitations
“Практически все” – слишком сильно сказано.
> То ли дело на С++, там можно еще к этому парочку UB добавить
ubsan
>Такое ощущение, что решения на С++ все сплошь очевидны.
Странное ощущение. В C++ есть устоявшиеся практики на тему “хорошо и плохо”, в Rust их пока что нет. И вот то чудище, что я привел вышел, вполне себе лежит в одной из основных библиотек языка.
> “Практически все” – слишком сильно сказано.
Нормально сказано, если пользоваться версией языка 11 и выше.
>> В C++ есть устоявшиеся практики на тему “хорошо и плохо”, в Rust их пока что нет.
Пока мне видится наоборот. Что ни проект, то свои правила. Недаром наверное пилится C++ Core Guidelines? И то, на него многие положат с пробором, я уверен. Да и не везде оно помогает.
Куда не влезть, то либо самопальная или эзотерическая система сборки, то ужасные косячные cmake листы. Хоть сейчас какие-то сдвиги в best practices к cmake есть, уже хлеб.
Шаблоны до сих пор: одни хейтят, другие упиваются (да что там шаблоны, даже макросы!). Где что разумно заюзать, это дискуссия же на неделю.
Обработка ошибок – кто на что горазд. Исключения std и boost, коды ошибок с nodiscard атрибутами, optional, теперь еще и expected в бусте, все смешать и подавать горячим.
Кто впихивает всякие наследования куда ни попадя, кто избегает их аки чумы.
Для кого буст грааль священный, для кого отстой тормозной (более того, встречал всякие мнения и про стл).
Продолжать можно еще и еще.
Да практически любую тему взять, исключая явное отстреливание выступающих частей (это что-ли практики на тему “хорошо и плохо”?), найдется два лагеря плюсистов, думающих диаметрально противоположно.
>> И вот то чудище, что я привел вышел, вполне себе лежит в одной из основных библиотек языка.
Так какая конкретно С++ практика из “хорошо и плохо” мешает написать аналогично?
Более того, на конфах плюсовых вроде такой код наоборот, считался бы образцовым. Могу тут конечно ошибаться.
И еще уверен, что если буст ты можешь поддержать одной левой, то и с этим справишься.
>> Нормально сказано, если пользоваться версией языка 11 и выше.
Я уже привел примеры. Если для кого-то это практически все, – ну окей.