Я хочу написать vec[idx] так, чтобы компилятор подтвердил, что я доказал корректность индекса и паники здесь быть не может, или чтобы компилятор сказал мне, что ничего не доказалось и паника возможна — ближе всего к этому подходит крейт no_panic, но он тоже кривой и имеет ложноположительные срабатывания (потому что работает через костыли)
И он бесполезен, потому что вынуждает перегружать код обработкой несуществующих ошибок и всё равно не способен отлавливать паники из сторонних библиотек
Собственно в статье уже упоминается один раздражающий меня пример — получение элемента массива по индексу (без специальных функций вроде get) — программист может захотеть использовать это, когда уверен, что индекс корректный и нет смысла перегружать код обработкой ошибок, которые никогда не случатся
С одной стороны, программист может доказать компилятору, что индекс корректный (например, проверив длину массива) — компилятор учтёт это и сгенерирует код, который никогда не будет выдавать ошибок (собственно в статье это показано)
С другой стороны, Rust не заставляет программиста доказывать это, или он может накосячить в доказательстве — в таком случае компилятор добавит свою проверку корректности индекса, которая может выплюнуть панику
И проблема тут в том, что программист НИКАК не может узнать, будет ли тут выплёвываться паника или нет, и он никак не может запретить компиляцию кода с паниками, отчего у меня сильно пригорало, когда я пытался написать код без паник
Вообще, к unwrap это тоже отчасти относится, потому что он может оказаться спрятан где-то глубоко внутри сторонней библиотеки — и программист об этом никак не узнает, пока не прочитает код этой самой библиотеки (или документацию, если создатель библиотеки оказался достаточно ответственный и упомянул наличие unwrap)
Если программист целенаправленно захотел заставить программу упасть явным написанием unwrap — это безопасно по всем параметрам, потому что всё работает в точности как задумано программистом и не имеет незапланированных побочных эффектов
Вы бы лучше вспомнили про паники, которые могут вываливаться в неожиданных местах — вот это реальная проблема Rust, на которую даже Линус ругался
Во-первых, речь тут не про unwrap, а во-вторых, всё равно не должен, потому что падение не является небезопасным для памяти событием (самое страшное, что может случиться, это утечка, но Rust на данный момент считает утечки безопасными)
После того, как я зарепортил в ejabberd крах, вызванный использованием строки там, где должно быть число — я считаю эрланг ненадёжной хренью. Блин, даже питон уже научили отлавливать такие детские ошибки
а так ли велика выгода за те ограничения, которые вводятся Растом?
После того, как мне неоднократно приходилось дебажить утечки в сишечных программах, ответственно заявляю — да, достаточно велика, «prevents most leaks» всё ещё намного лучше чем «prevents no leaks»
100% кода Rust зависят от библиотек, которые используют unsafe, потому что стандартная библиотека
Одна из фишек unsafe в том, что при поломке он сужает круг подозреваемых. Не надо вычитывать тонны кода почти всей программы, достаточно пробежаться по unsafe-фрагментам, которые выполнялись перед поломкой
Так что тут надо не заявлять категоричное «используют unsafe хотя бы один раз», а посчитать, какой конкретно процент кода является unsafe (без учёта и с учётом стандартной библиотеки), и этот процент примерно покажет, на сколько проще отлаживать поломки по сравнению с условными сишечками
Вы пробовали написать низкоуровневый код на расте без unsafe?
В чём смысл вопроса? unsafe для того и существует, чтобы предоставить программисту возможность реализовывать и самостоятельно проверять вещи, которые не способен проверить safe Rust, и изолировать эти вещи от остальной программы в этих самых unsafe-блоках (в околосишечных языках абсолютно весь код является unsafe, поэтому Rust тут безопаснее)
Может, потому что делать иначе просто нет смысла? Для немутабельной передачи с сохранением жизни исходной переменной уже есть передача по ссылке. А владение с запретом мутабельности для меня звучит как-то противоречиво, это уже как будто и не владение совсем
Ну теоретически всё ещё можно пробросить pub struct LambdaHolder или pub fn give_me_your_lambda в стороннюю библиотеку (но писать ещё один громоздкий пример я не буду)
А делать две разных логики для публичных и приватных функций — по-моему только ещё больше всех запутает
Я настолько глубоко не копал, но подозреваю, что компилятор просто не даст такое сделать
Строки, которые прописываются в строковых литералах (let s = "Hello, World!";) и предположительно будут помещены компилятором в сегмент данных, имеют другой тип &str — то есть ссылка на кусок строки без мутабельности (а точнее &'static str, что означает, что эта ссылка остаётся валидной в течение всей жизни программы)
Потому что программист так захотел и именно так объявил в сигнатуре функции
Как функция с иммутабельным параметром
(в случае иммутабельного параметра для начала)
Я тут у вас вижу повторяющееся заблуждение. Владелец параметра может делать с ним что угодно, в том числе превратить иммутабельное значение в мутабельное:
fn my_func(v: String) {
let mut v = v;
v.push_str("мутирую азаза");
}
Наличие или отсутствие мутабельности у значений — это больше защита от случайных опечаток, чтобы программист случайно не сделал то что изначально не планировал (но если всё же запланировал, то он может явно объявить мутабельность как в примере выше)
А вот мутабельность в ссылках это будет уже совсем другой разговор
После вызова my_func(s) владельцем параметра становится функция. Когда работа функции завершается, у параметра больше не остаётся владельца. Раз владельца больше нет — объект автоматически уничтожается и освобождается связанная с ним память. Этот факт защищает от утечек памяти, а невозможность использовать параметр повторно — от use-after-free
Я хочу написать
vec[idx]
так, чтобы компилятор подтвердил, что я доказал корректность индекса и паники здесь быть не может, или чтобы компилятор сказал мне, что ничего не доказалось и паника возможна — ближе всего к этому подходит крейт no_panic, но он тоже кривой и имеет ложноположительные срабатывания (потому что работает через костыли)И он бесполезен, потому что вынуждает перегружать код обработкой несуществующих ошибок и всё равно не способен отлавливать паники из сторонних библиотек
Собственно в статье уже упоминается один раздражающий меня пример — получение элемента массива по индексу (без специальных функций вроде get) — программист может захотеть использовать это, когда уверен, что индекс корректный и нет смысла перегружать код обработкой ошибок, которые никогда не случатся
С одной стороны, программист может доказать компилятору, что индекс корректный (например, проверив длину массива) — компилятор учтёт это и сгенерирует код, который никогда не будет выдавать ошибок (собственно в статье это показано)
С другой стороны, Rust не заставляет программиста доказывать это, или он может накосячить в доказательстве — в таком случае компилятор добавит свою проверку корректности индекса, которая может выплюнуть панику
И проблема тут в том, что программист НИКАК не может узнать, будет ли тут выплёвываться паника или нет, и он никак не может запретить компиляцию кода с паниками, отчего у меня сильно пригорало, когда я пытался написать код без паник
Вообще, к unwrap это тоже отчасти относится, потому что он может оказаться спрятан где-то глубоко внутри сторонней библиотеки — и программист об этом никак не узнает, пока не прочитает код этой самой библиотеки (или документацию, если создатель библиотеки оказался достаточно ответственный и упомянул наличие unwrap)
Если программист целенаправленно захотел заставить программу упасть явным написанием unwrap — это безопасно по всем параметрам, потому что всё работает в точности как задумано программистом и не имеет незапланированных побочных эффектов
Вы бы лучше вспомнили про паники, которые могут вываливаться в неожиданных местах — вот это реальная проблема Rust, на которую даже Линус ругался
Во-первых, речь тут не про unwrap, а во-вторых, всё равно не должен, потому что падение не является небезопасным для памяти событием (самое страшное, что может случиться, это утечка, но Rust на данный момент считает утечки безопасными)
После того, как я зарепортил в ejabberd крах, вызванный использованием строки там, где должно быть число — я считаю эрланг ненадёжной хренью. Блин, даже питон уже научили отлавливать такие детские ошибки
Если программист хочет падать, он должен явно прописать намерение упасть в коде, иначе о какой надёжности вообще может идти речь
После того, как мне неоднократно приходилось дебажить утечки в сишечных программах, ответственно заявляю — да, достаточно велика, «prevents most leaks» всё ещё намного лучше чем «prevents no leaks»
100% кода Rust зависят от библиотек, которые используют unsafe, потому что стандартная библиотека
Одна из фишек unsafe в том, что при поломке он сужает круг подозреваемых. Не надо вычитывать тонны кода почти всей программы, достаточно пробежаться по unsafe-фрагментам, которые выполнялись перед поломкой
Так что тут надо не заявлять категоричное «используют unsafe хотя бы один раз», а посчитать, какой конкретно процент кода является unsafe (без учёта и с учётом стандартной библиотеки), и этот процент примерно покажет, на сколько проще отлаживать поломки по сравнению с условными сишечками
В чём смысл вопроса? unsafe для того и существует, чтобы предоставить программисту возможность реализовывать и самостоятельно проверять вещи, которые не способен проверить safe Rust, и изолировать эти вещи от остальной программы в этих самых unsafe-блоках (в околосишечных языках абсолютно весь код является unsafe, поэтому Rust тут безопаснее)
Сочетание безопасности и скорости (языки с GC безопасные но медленные, околосишечные языки быстрые но небезопасные)
Во-первых, закон Мура вроде как несколько раз хоронили
Во-вторых, судя по этой фразе, именно из-за таких людей как вы появился закон Вирта)
Добавить libfoo в эти самые другие роли, не?
Может, потому что делать иначе просто нет смысла? Для немутабельной передачи с сохранением жизни исходной переменной уже есть передача по ссылке. А владение с запретом мутабельности для меня звучит как-то противоречиво, это уже как будто и не владение совсем
При передаче владения в подфункцию область жизни перемещается в эту самую подфункцию, вот и удаляется в конце области подфункции
Ну теоретически всё ещё можно пробросить
pub struct LambdaHolder
илиpub fn give_me_your_lambda
в стороннюю библиотеку (но писать ещё один громоздкий пример я не буду)А делать две разных логики для публичных и приватных функций — по-моему только ещё больше всех запутает
Я настолько глубоко не копал, но подозреваю, что компилятор просто не даст такое сделать
Строки, которые прописываются в строковых литералах (
let s = "Hello, World!";
) и предположительно будут помещены компилятором в сегмент данных, имеют другой тип&str
— то есть ссылка на кусок строки без мутабельности (а точнее&'static str
, что означает, что эта ссылка остаётся валидной в течение всей жизни программы)Ну, это не создаёт никаких уязвимостей, связанных с повреждением памяти, так что нет технических причин объявлять это unsafe ¯\_(ツ)_/¯
Лямбды тоже можно таскать глобально по всей программе
Потому что программист так захотел и именно так объявил в сигнатуре функции
Я тут у вас вижу повторяющееся заблуждение. Владелец параметра может делать с ним что угодно, в том числе превратить иммутабельное значение в мутабельное:
Наличие или отсутствие мутабельности у значений — это больше защита от случайных опечаток, чтобы программист случайно не сделал то что изначально не планировал (но если всё же запланировал, то он может явно объявить мутабельность как в примере выше)
А вот мутабельность в ссылках это будет уже совсем другой разговор
Так он есть прямо в посте:
После вызова
my_func(s)
владельцем параметра становится функция. Когда работа функции завершается, у параметра больше не остаётся владельца. Раз владельца больше нет — объект автоматически уничтожается и освобождается связанная с ним память. Этот факт защищает от утечек памяти, а невозможность использовать параметр повторно — от use-after-free