четверг, 9 марта 2023 г.

[prog.impressions] Любопытная статья про проблемы с unsafe Rust и отсутствием таковых в Zig

Со мной поделились ссылкой на статью When Zig is safer and faster than Rust. Показалась любопытной, хоть далек от Rust, и еще более далек от Zig.

В общем, решил поделиться и я :)

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


Больше всего меня впечатлил вот этот кусочек синтаксиса Zig-а:

const STACK_TOP = 256;
const VM = struct {
    // pointer to unknown number of items
    stack_top: [*]Value,
    // like a rust slice:
    // contains a [*]Value + length
    // has bounds checking too
    stack: []Value,
    // alternative to slices when
    // N is a comptime known constant
    stack_alt: *[STACK_TOP]Value
};

Как по мне, как это и умно, и хитро, и практично.

Глядя на этот фрагмент подумалось, что в C++ можно самостоятельно замутить что-то подобное. Например, класс raw_ptr<T>, который просто хранит указатель и позволяет получить его значение, но не допускает адресной арифметики. А также классы dynamic_span<T> и static_span<T, N>, которые описывают последовательность расположенных друг за другом объектов типа T. Для span-классов возможны операции итерации по содержимому, а также преобразования из static_span в dynamic_span. Соответственно, для доступа к элементу по индексу доступны и operator[], и метод at.

Хотя я бы отошел от принятого в STL соглашения о том, что operator[] не делает проверки в run-time, а at делает. И сделал бы так, чтобы operator[] осуществлял бы проверки в run-time. А для доступа без проверок использовался бы какой-то метод с некрасивым и бросающимся в глаза именем, вроде unsafe_get.

Более того, раз уж в C++ сообществе заговорили о том, чтобы превратить C++ в безопасный язык (не то, чтобы я верил в подобные перспективы, но раз пытаются, то зачем мешать?), то можно было бы пойти и дальше: сделать классы вроде raw_ptr, dynamic_span, static_span и т.п., частью языка. И таки ввести в язык что-то вроде "эпох", "поколений" или "ревизий". Чтобы начиная с какой-то "ревизии" нельзя было оперировать голыми указателями. Ну вот вообще. Только специальными классами. С автоматическим преобразованием raw_ptr в соответствующий указатель при обращении к C API, но только лишь в этом случае.

Эх, мечты, мечты :(


Еще одно впечатление связано с тем, что мне все еще непонятен хайп вокруг Rust-а.

Одно дело, если бы Rust позиционировался исключительно как околосистемный язык, полноценная замена и C, и C++, и Ada. Но, судя по описанным в упомянутой статье проблемам с unsafe Rust, это как бы не совсем так. По меньшей мере есть что улучшать в языке для того, чтобы на нем было удобно программировать в unsafe.

Однако же, изрядное количество шума вокруг Rust-а создавали (может и сейчас создают, просто уже не слежу) пользователи всяких там Ruby и Python-ов. Мол, раньше мы писали на динамически-типизированном языке и имели кучу разных проблем и с производительностью, и с сопровождаемостью... А как попробовали Rust, так волосы сразу стали гладкими и шелковистыми ;)

ИМХО, очень странно выглядят попытки применять Rust для высокоуровневого прикладного программирования.

По моему разумению (или заблуждению, тут уж и сам не понимаю) приходится так делать потому, что в нулевых годах слишком уж все увлеклись Java и C#, которые безопасные, но не нативные. Т.е. не производят ни Java, ни C# сразу нативный код. Вместо этого есть промежуточное представление, которое тем или иным образом транслируется в нативный код уже при исполнении программы.

И вот когда увлечение "write once, run everywhere" таки логично сошло до оправданного минимума, то оказалось, что удобного и безопасного нативного языка для прикладного программирования-то и нет.

Ну вот сходу вспоминаются разве что Eiffel (который старый, не модный, сильно платный и нифига не приспособленный для фигак-фигак-и-в-продакшен), Object Pascal в разных его проявлениях (который старый и незаслуженно нелюбимый массами из-за begin/end, хотя казалось бы какая нафиг...), да и не взлетевший D (он то может и взлетел, но низенько-низенько). Вот, собственно, и все, что можно вспомнить из середины-конца нулевых.

Раньше всех сориентировались в Google и сделали Go. Который как раз таки и простой, и безопасный, и нативный, и в меру быстрый. Но убогий :) Да и заточенный только под определенную нишу.

Вот и получается, что Ruby-истам и Python-истам, которых не устраивает скорость и надежность их кода на динамически-типизированных языках, переходить особо-то и не на что. Java и C# в пролете изначально, т.к. их сразу можно было использовать, но почему-то не использовали. Go может подойти, а может и нет. Таки убогость Go никуда не девается.

А тут Rust, нативный, быстрый, безопасный, да еще и модный, и молодежный. Bingo! :)))

Хотя, как по мне, будь какой-нибудь стабильный D1 с поддержкой от какой-то крупной корпорации (или их группы), то смотреть на Rust для прикладной разработки и не пришлось бы.