Эссе о разработке игр, мышлении и книгах

Почему мне не нравится Rust

Во второй раз перелистал документацию Rust, прошлый заход случился лет 5 назад.

Думал, что-нибудь изменится в моём восприятии этого языка, но нет. Как и в прошлый раз, начинается всё хорошо — норм язык, а потом он начинает нравиться всё меньше и меньше.

И похоже я понял, что меня в нём задевает.

Хороший инструмент не ограничивает своего пользователя, поскольку разработчик инструмента никогда не предугадает все варианты использования.

Молоток не должен требовать сертифицированных гвоздей с крышкой фиксированной формы. Библиотека не должна навязывать архитектурные решения. Язык программирования не должен насильно заворачивать модель программы в удобное создателям языка русло.

При этом молоток может быть оптимизирован под сертифицированные гвозди, библиотека может предлагать архитектурные решения, а язык может иметь средства, упрощающие разработку программ конкретногой архитектуры.

И это не какое-то мелкое требование. По моим ощущениям, самые геморройные, самые идиотские проблемы в моей карьере возникали из-за того, что разработчики какого-нибудь инстурмента решили, что делать штуки можно только одним, самым правильным способом.

Если мы посмотрим на большинство языков программирования, то увидим разрешающую логику описания программ: программист волен гемороиться только с тем платить только за то, что считает необходимым для конкретного проекта.

В Python мы можем написать самый кривой код, если он нас устраивает. Интерпретатор не заставит ставить numpy, писать аннотации, запускать статическую верификацию типов, etc. Если мы считаем это необходимым для проекта — реализум, но можем и «схалявить» — это наша ответственность.

В Julia мы можем не загоняться по типам и нормально жить. Если для проекта требуется JIT и скорость, мы можем больше времени вложить в проработку типов. Там где надо. А где не надо — не вложить.

Даже в C++ можно выбирать разные уровни проработки кода. От C-подобного, до хардкора с контролем контрактов через шаблоны.

И это хорошо. Разрешающая логика позволяет экономить время и мыслетопливо.

Rust же поступает наоборот — сходу выдвигает повышенные требования. Заставляет тратить время на то, на что его тратить именно в данный момент в данной задаче может быть и не надо. Сразу необходимо оптимизировать код и даже не под производительность или использование памяти, а под избежание нескольких частных случаев проблем с памятью.

Это раздражает.

Часто в навязанном контроле нет необходимости. Контроль памяти не нужен для прототипов, для одноразовых утилит, для любого кода, работа которого может быть потеряна без урона и который не торчит во внешку. То есть для огромного количества программ.

И ведь можно было сделать лучше. Вместо unsafe блоков, ввести safe. Не навязывать своё видение безопасности, а разрешить повышать ограничения при необходимости. Хочешь — делаешь безопасной функцию, хочешь — модуль, хочешь — весь проект.

Пишет разработчик прототип на костылях, тот становится популярным, пользователи шлют pull requests с тестами и рефакторингом в safe блоки, софт становится стабильным и безопасным. Не надо тратить силы на преждевременные оптимизации.

P.S. Оговорка об ограничениях инструментов. В некоторых случаях они обоснованы. Например, если от работы инструмента зависят жизни людей. Но это небольшая часть отрасли. Такой софт исторически пользуется дополнительными штуками, направленными на повышение надёжности. Разрабатывать общеупотребительный инструмент, ориентируясь на частные случаи — так себе идея.