Почему в расте отсутствует выброс исключений?
От: vaa  
Дата: 22.11.22 03:18
Оценка:
Почему в расте отсутствует выброс исключений? Это же удобный способ передачи управления.
Или быть может существует более продвинутый механизм наподобие Common Lisp Condition System ?
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re: Почему в расте отсутствует выброс исключений?
От: johny5 Новая Зеландия
Дата: 22.11.22 04:30
Оценка: 14 (2) +4 -1
Здравствуйте, vaa, Вы писали:

vaa>Почему в расте отсутствует выброс исключений? Это же удобный способ передачи управления.


Это достаточно сложный, спорный вопрос со множеством мнений.

Кому то нравится когда контракт возвращаемого результата прописан в результирующем значении функции явно (Result<T>) без скрытого контракта на взвесь "каких то" exceptions, которые код может кинуть (исключения не документируются кодом. Хорошо если в комментах что то написано, но никаких гарантий что не прилетит что то ещё). Кому то нравится обрабатывать ошибку на месте, потому что когда она выплёвывается выше и выше — всё меньше шансов обработать её правильно.

Исключения добавляют второй слой обработки ошибок, и часто становится непонятно, ошибка, например, открытия файла — это исключение или просто вернуть код ошибки. Часто приводит к дупликации API для обоих стилей. Исключения легко забыть необработать, пропущенный stoi() гденть в невинном месте может убить сервер.

То что есть в Расте тоже удобно, ошибки возвращаются явно и если нет нужды обрабатывать на месте, просто прокидываются вверх '?' оператором. Но каждое написание '?' заставляет тебя на секунду задуматься, что можно тут сделать если операция вернула ошибку.

Я на самом деле не против исключений. Просто рассматриваю как альтернативу для сценариев где это действительно нужно. Например в С++ из конструктора никак не вернуть код ошибки и используются исключения. Но в Расте конструкторов нет — всё, обычные функции.

Исключения добавить будет можно всегда, вот тут нагуглился RFC0243 который они ещё обсуждают. Помоему он хорошо резюмируется вот такой цитатой:

No expressivity is added, only convenience. Some object to "there's more than one way to do it" on principle.



vaa>Или быть может существует более продвинутый механизм наподобие Common Lisp Condition System ?

Не слышал.
Re[2]: Почему в расте отсутствует выброс исключений?
От: johny5 Новая Зеландия
Дата: 30.11.22 06:23
Оценка: 5 (1) -1
Здравствуйте, johny5, Вы писали:

J>Здравствуйте, vaa, Вы писали:


vaa>>Почему в расте отсутствует выброс исключений? Это же удобный способ передачи управления.


Кстате обнаружил для себя panic!, оказывается он не убивает приложение а только текущий поток (ну и приложение если поток был главным). Tokio как то хитро это использует и просто выплёвывает запаниковавшие короутины, продолжая работать дальше. Чем то похоже на эксепшионы.

На обработчик panic можно ставить свою процедуру через set_hook. Правда, насколько я понял, это глобальный обработчик и он не может остановить убивание провинившегося потока.
Просветите если чего недопонял, плиз.
Re[3]: Почему в расте отсутствует выброс исключений?
От: FR  
Дата: 30.11.22 07:03
Оценка: +1
Здравствуйте, johny5, Вы писали:

J>Кстате обнаружил для себя panic!, оказывается он не убивает приложение а только текущий поток (ну и приложение если поток был главным). Tokio как то хитро это использует и просто выплёвывает запаниковавшие короутины, продолжая работать дальше. Чем то похоже на эксепшионы.


Технически паники по умолчанию практически аналогичны исключениям С++, так же происходит раскрутка стека. Но вот перехватить их можно только для потока целиком. И кроме того есть режим компиляции panic = abort и при его использовании любая паника в любом потоке прибивает процесс, так что полагаться на паники для обработки ошибок нельзя.


J>На обработчик panic можно ставить свою процедуру через set_hook. Правда, насколько я понял, это глобальный обработчик и он не может остановить убивание провинившегося потока.

J>Просветите если чего недопонял, плиз.

Да все правильно, на уровне потока вполне можно перехватывать, перезапускать же придется только ручным созданием нового потока.
Re[3]: Почему в расте отсутствует выброс исключений?
От: flаt  
Дата: 30.11.22 09:04
Оценка:
Здравствуйте, johny5, Вы писали:

J>Кстате обнаружил для себя panic!, оказывается он не убивает приложение а только текущий поток (ну и приложение если поток был главным). Tokio как то хитро это использует и просто выплёвывает запаниковавшие короутины, продолжая работать дальше. Чем то похоже на эксепшионы.


Это они и есть.

J>На обработчик panic можно ставить свою процедуру через set_hook. Правда, насколько я понял, это глобальный обработчик и он не может остановить убивание провинившегося потока.

J>Просветите если чего недопонял, плиз.


https://doc.rust-lang.org/std/panic/fn.catch_unwind.html — вот официальный способ перехвата паники (если не компилировать с panic=abort). По сути, try/catch.


https://doc.rust-lang.org/std/panic/fn.set_hook.html — это не обработка, а просто колбэк при панике, чтобы вывести сообщение.
Отредактировано 30.11.2022 9:09 flаt . Предыдущая версия .
Re[3]: Почему в расте отсутствует выброс исключений?
От: flаt  
Дата: 30.11.22 09:09
Оценка:
Здравствуйте, johny5, Вы писали:

J>Кстате обнаружил для себя panic!,


Что значит, обнаружил? Это описывается в "The book", которую нужно прочитать в первую неделю знакомства с языком.

Как можно что-то использовать, даже не прочитав документацию? Будь-то ЯП или API.
Re[4]: Почему в расте отсутствует выброс исключений?
От: DarkEld3r  
Дата: 30.11.22 09:21
Оценка: 18 (1)
Здравствуйте, FR, Вы писали:

FR>Технически паники по умолчанию практически аналогичны исключениям С++, так же происходит раскрутка стека. Но вот перехватить их можно только для потока целиком.


Что значит второе предложение?

FR>И кроме того есть режим компиляции panic = abort и при его использовании любая паника в любом потоке прибивает процесс, так что полагаться на паники для обработки ошибок нельзя.


Уточню: это проблема только если мы пишем библиотеку. И даже так мне попадались библиотеки у которых в документации было написано, что требуется panic=unwind. Ещё есть вот такой костыль, чтобы явно это требовать, правда только для найтли: https://stackoverflow.com/a/69273385/7752098

Справедливости ради, в подавляющем большинстве случаев никто обработку ошибок на паниках не делает.
Re: Почему в расте отсутствует выброс исключений?
От: m2user  
Дата: 30.11.22 09:25
Оценка: 12 (1)
vaa>Почему в расте отсутствует выброс исключений? Это же удобный способ передачи управления.
vaa>Или быть может существует более продвинутый механизм наподобие Common Lisp Condition System ?

По этой теме есть наглядная презентация (и видео с докладом) Александреску
https://cppeurope.com/wp-content/uploads/2018/02/Andrei_Alexandrescu_Expect_the_expected_slides.pdf
std::experimental::expected<E, T> в C++ это ближайший аналог Result<T, E> в Rust.

Вот ещё бложик https://dave.cheney.net/2012/12/11/andrei-alexandrescu-on-exceptions
Там обсуждаются другие доклады Александреску, в т.ч. есть сравнение с обработкой ошибок в Go.
Re[5]: Почему в расте отсутствует выброс исключений?
От: FR  
Дата: 30.11.22 09:42
Оценка:
Здравствуйте, DarkEld3r, Вы писали:

FR>>Технически паники по умолчанию практически аналогичны исключениям С++, так же происходит раскрутка стека. Но вот перехватить их можно только для потока целиком.


DE>Что значит второе предложение?


Означает склероз, про catch_unwind знал, но на практике не использовал.
Ну и в документации прямо не рекомендуется его использовать как замену try/catch, хотя конечно все-равно будут это делать.

FR>>И кроме того есть режим компиляции panic = abort и при его использовании любая паника в любом потоке прибивает процесс, так что полагаться на паники для обработки ошибок нельзя.


DE>Уточню: это проблема только если мы пишем библиотеку. И даже так мне попадались библиотеки у которых в документации было написано, что требуется panic=unwind.


Практически это нарушает универсальность такой библиотеки.

DE>Ещё есть вот такой костыль, чтобы явно это требовать, правда только для найтли: https://stackoverflow.com/a/69273385/7752098


Да полезная вещь.

DE>Справедливости ради, в подавляющем большинстве случаев никто обработку ошибок на паниках не делает.


Ну так или иначе все-таки делают, в конечном счете так и до исключений может дойти
Re[3]: Почему в расте отсутствует выброс исключений?
От: νsb Казахстан  
Дата: 30.11.22 09:51
Оценка: +1
Здравствуйте, johny5, Вы писали:

J>Кстате обнаружил для себя panic!, оказывается он не убивает приложение а только текущий поток (ну и приложение если поток был главным). Tokio как то хитро это использует и просто выплёвывает запаниковавшие короутины, продолжая работать дальше. Чем то похоже на эксепшионы.


J>На обработчик panic можно ставить свою процедуру через set_hook. Правда, насколько я понял, это глобальный обработчик и он не может остановить убивание провинившегося потока.

J>Просветите если чего недопонял, плиз.

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

Для своих приложений в теории — можно. Это действительно очень похоже на исключения. Но это будет как с go, вся стандартная библиотека и все сторонние библиотеки используют другой механизм обработки ошибок, поэтому тут или всё переписывать/оборачивать, или будет в проекте две системы обработки ошибок.

В целом лучше писать код так, как пишут другие.
Отредактировано 30.11.2022 9:52 vsb . Предыдущая версия .
Re[6]: Почему в расте отсутствует выброс исключений?
От: DarkEld3r  
Дата: 30.11.22 12:03
Оценка: +1
Здравствуйте, FR, Вы писали:

FR>Практически это нарушает универсальность такой библиотеки.


Да, но те примеры, что я помню — это были скорее даже не библиотеки, а фреймворки, причём специализированные (например, substrate), так что это не проблема. Ну и там естественно не вся обработка ошибок на паниках сделана, просто библиотека полагается на возможность их перехватывать.

FR>Ну так или иначе все-таки делают, в конечном счете так и до исключений может дойти


Надеюсь, что нет. (:

Но так-то у паник уже есть всё необходимое для полноценных исключений: у паники можно получить конкретный тип, их можно пробрасывать дальше после перехвата (resume_unwind). Не хватает разве что удобного сахара, но думаю, что его принципиально не делают.
Re[4]: Почему в расте отсутствует выброс исключений?
От: alex_public  
Дата: 01.12.22 18:53
Оценка:
Здравствуйте, νsb, Вы писали:

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

νsb>Для своих приложений в теории — можно. Это действительно очень похоже на исключения. Но это будет как с go, вся стандартная библиотека и все сторонние библиотеки используют другой механизм обработки ошибок, поэтому тут или всё переписывать/оборачивать, или будет в проекте две системы обработки ошибок.
νsb>В целом лучше писать код так, как пишут другие.

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

В любом приложение обязательно должно быть два отдельных способа: обработки ошибок и обработки исключительных ситуаций. Это принципиально разные ситуации с разной необходимой реакций и с разными удобными способами реализации. В первом случае (например при попытке открытия заблокированного файла) приложение должно уведомить (обычно через GUI) пользователя о проблеме и спокойно продолжить выполнение. В этом случае очевидно необходима обработка по месту (часто прямо в той же функции, где открываем файл), поэтому штуки типа классических исключений здесь максимально неудобны (из-за необходимости обкладывать каждый вызов в try/catch). А вот во втором случае (исключительных ситуаций, типа нехватки памяти на машине) приложение обычно просто завершает свою работу, возможно записав что-то в лог (или отправив отчёт на сервер). И здесь наоборот максимально удобен подход с исключениями, в виде одного глобального обработчика на приложение или поток.

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

Rust же здесь выгодного отличается наличием двух отдельных механизмов, каждый под свою ситуацию. Паники для обработки исключительных ситуаций и Result для обычных ошибок.
Re[4]: Почему в расте отсутствует выброс исключений?
От: T4r4sB Россия  
Дата: 01.12.22 19:03
Оценка: 9 (1)
Здравствуйте, FR, Вы писали:

FR>И кроме того есть режим компиляции panic = abort и при его использовании любая паника в любом потоке прибивает процесс

Но будь осторожен. Я комбо словил, случается именно в вин7 в х32 проге. Там паника это особая инструкция которая кидает исключение, а винда гасит исключения, что произошли внутри вндПрок, просто гасит и продолжает исполнение
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[5]: Почему в расте отсутствует выброс исключений?
От: vsb Казахстан  
Дата: 01.12.22 22:22
Оценка: +3
Ну лично я с такой постановкой вопроса не согласен. Я пишу серверный софт и у меня 99.99% потенциальных ошибок вроде открытия файла — фатальные. Но не настолько фатальные, чтобы ронять приложение, а настолько фатальные, чтобы размотать стек и на запрос ответил универсальный обработчик ошибок, залоггировав её и вернув 500 код. Мне эта ваша обработка ошибок нафиг не сдалась. Раз в год из тысячи одну такую ошибку нужно обрабатывать специальным образом. Всё остальное время в лучшем случае обработка сводится к доцеплению контекстной информации, чтобы стектрейс пожирней сделать. А чаще всего обработка сводится к отсутствию этой самой обработки.

Поэтому мне что раст, что голанг жутко неудобны и я не понимаю, как на них люди могут что-то писать. А вот обычные тупые исключения вроде питоновских — то, что доктор прописал.
Отредактировано 01.12.2022 22:24 vsb . Предыдущая версия . Еще …
Отредактировано 01.12.2022 22:24 vsb . Предыдущая версия .
Отредактировано 01.12.2022 22:23 vsb . Предыдущая версия .
Re[6]: Почему в расте отсутствует выброс исключений?
От: johny5 Новая Зеландия
Дата: 01.12.22 22:25
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Поэтому мне что раст, что голанг жутко неудобны и я не понимаю, как на них люди могут что-то писать. А вот обычные тупые исключения вроде питоновских — то, что доктор прописал.


На днях я попробовал Rocket crate, он как раз даёт именно то что вы сейчас описали. Делаешь unwrap() на открытие/чтение файла и сервер возвращает error 500, продолжая при этом работать.
Re[6]: Почему в расте отсутствует выброс исключений?
От: alex_public  
Дата: 01.12.22 22:51
Оценка: +1
Здравствуйте, vsb, Вы писали:

vsb>Ну лично я с такой постановкой вопроса не согласен. Я пишу серверный софт и у меня 99.99% потенциальных ошибок вроде открытия файла — фатальные. Но не настолько фатальные, чтобы ронять приложение, а настолько фатальные, чтобы размотать стек и на запрос ответил универсальный обработчик ошибок, залоггировав её и вернув 500 код. Мне эта ваша обработка ошибок нафиг не сдалась. Раз в год из тысячи одну такую ошибку нужно обрабатывать специальным образом. Всё остальное время в лучшем случае обработка сводится к доцеплению контекстной информации, чтобы стектрейс пожирней сделать. А чаще всего обработка сводится к отсутствию этой самой обработки.


Ну, то что ты описал — это как раз случай не исключительной ситуации, а обычной обработки ошибок и соответственно удобнее это обрабатывать не исключениями, а через Result.

А насчёт твоего универсального обработчика ошибок... Так он всегда возвращает именно 500? А если где-то надо 404 вернуть или 401, то как тогда? А если случается OOM, то он тоже пытается вернуть запрос (на создание которого опять же нужна память, которой уже нет) с 500?

vsb>Поэтому мне что раст, что голанг жутко неудобны и я не понимаю, как на них люди могут что-то писать. А вот обычные тупые исключения вроде питоновских — то, что доктор прописал.


А что именно неудобно в работе с Result?
Re[7]: Почему в расте отсутствует выброс исключений?
От: johny5 Новая Зеландия
Дата: 01.12.22 22:59
Оценка:
_>Ну, то что ты описал — это как раз случай не исключительной ситуации, а обычной обработки ошибок и соответственно удобнее это обрабатывать не исключениями, а через Result.

_>А насчёт твоего универсального обработчика ошибок... Так он всегда возвращает именно 500? А если где-то надо 404 вернуть или 401, то как тогда? А если случается OOM, то он тоже пытается вернуть запрос (на создание которого опять же нужна память, которой уже нет) с 500?


Тут согласен, 500 это если всё пошло пузырями, но в целом нужно обрабатывать ошибку и возвращать соответствующую, форматированную страницу.
Re[7]: Почему в расте отсутствует выброс исключений?
От: vsb Казахстан  
Дата: 01.12.22 23:01
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Ну, то что ты описал — это как раз случай не исключительной ситуации, а обычной обработки ошибок и соответственно удобнее это обрабатывать не исключениями, а через Result.


Нет, удобней это обрабатывать именно исключениями. Т.к. при этом мне не нужно писать никакого кода.

_>А насчёт твоего универсального обработчика ошибок... Так он всегда возвращает именно 500? А если где-то надо 404 вернуть или 401, то как тогда? А если случается OOM, то он тоже пытается вернуть запрос (на создание которого опять же нужна память, которой уже нет) с 500?


Ну вот в 1 случае из 10 000 мне надо вернуть что-то кроме 500. И я для этого напишу эти 4 строчки с обработчиком. А в остальных 9999 случаях не напишу. И даже думать про это не буду, ну кроме как на уровне архитектуры, типа транзакции для БД и тд.

OOM в жаве это отдельная иерархия, но в целом — да, если отвечать на вопрос — пытается. И у него скорей всего получится, т.к. на нижнем уровне там всё используется в пулах преаллоцированных. Хотя, конечно, в условиях OOM всё будет плохо. У меня такой ситуации практически не бывает, но если про это задумываться, я при OOM предпочёл бы просто завершить процесс.

_>А что именно неудобно в работе с Result?


Ну в го неудобно то, что там под каждым вызовом функции еще 3 строки на обработку err. В расте сахарок сделали, но всё равно везде Result-ы мусорят же. Зачем мне это видеть.

Я от раста не требую исключений, язык всё же не про это. Но про неудобство всё равно отметить хотел.
Отредактировано 01.12.2022 23:06 vsb . Предыдущая версия . Еще …
Отредактировано 01.12.2022 23:03 vsb . Предыдущая версия .
Отредактировано 01.12.2022 23:03 vsb . Предыдущая версия .
Re[5]: Почему в расте отсутствует выброс исключений?
От: FR  
Дата: 02.12.22 16:17
Оценка:
Здравствуйте, T4r4sB, Вы писали:

FR>>И кроме того есть режим компиляции panic = abort и при его использовании любая паника в любом потоке прибивает процесс

TB>Но будь осторожен. Я комбо словил, случается именно в вин7 в х32 проге. Там паника это особая инструкция которая кидает исключение, а винда гасит исключения, что произошли внутри вндПрок, просто гасит и продолжает исполнение

Что-то смутно знакомое, с таким гашением, такое кажется и в C++ ловил на winapi, и оно точно есть в VCL с С++ builder.
Re[6]: Почему в расте отсутствует выброс исключений?
От: T4r4sB Россия  
Дата: 02.12.22 18:14
Оценка: 18 (1)
Здравствуйте, FR, Вы писали:

FR>Что-то смутно знакомое, с таким гашением, такое кажется и в C++ ловил на winapi, и оно точно есть в VCL с С++ builder.


А дело не в языке, а вот в этом: https://learn.microsoft.com/en-us/cpp/intrinsics/fastfail?view=msvc-170

Support for the native fast fail mechanism began in Windows 8. Windows operating systems that don't support the fast fail instruction natively will typically treat a fast fail request as an access violation

В семёрке это исключение

И в этом: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-wndproc

Behavior type How the system handles uncaught exceptions
1 The system suppresses any uncaught exceptions.
2 The system first terminates the process, and then the Program Compatibility Assistant (PCA) offers to fix it the next time you run the application. You can disable the PCA mitigation by adding a Compatibility section to the application manifest.
3 The system calls the exception filters but suppresses any uncaught exceptions when it leaves the callback scope, without invoking the associated handlers.

The following table shows how a 64-bit version of the Windows operating system, and WOW64, handles uncaught exceptions. Notice that behavior type 2 applies only to the 64-bit version of the Windows 7 operating system and later.
Operating system WOW64 64-bit Windows
Windows XP 3 1
Windows Server 2003 3 1
Windows Vista 3 1
Windows Vista SP1 1 1
Windows 7 and later 1 2

Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.