Здравствуйте, vsb, Вы писали:
vsb>Для этого ему сначала надо взломать сервер (:
Для этого не нужно взламывать сервер, конечно пользователю показываются
ошибки которые он может исправить: ввести логин и пароль, загрузить другой файл,
предоставить правильную ссылку и так далее.
Z>>И большинство софта с которым я работаю в общем-то "популярные" ошибки пользователя так и обрабатываются как я указал в исходном сообщении. Z>>Если пришел код 401/403 по HTTP то почти любое приложение умеет преобразовать его в диалог повторного Z>>запроса логина и пароля
vsb>Вот это как раз и делается очень удобно с исключениями. Заводится одно исключение UnauthorizedException которое может бросить кто угодно и которое на уровне общего обработчика преобразуется в соответствующий HTTP-код.
И в результате будет сделано как раз то, что вы говорили что никто не делает: Z>а сообщение о том что случилось и как это исправить. Z>Для это и нужно контролировать прохождение ошибки сверху вниз и добавлять к ней нужный Z>контекст.
Мы перехватываем ошибки/коды типа 401,403 плюс ошибки связанные со сроком действия токена
и бросаем вместо него UnauthorizedException
Z>>Большинство рабочего софта (IDE, видео редакторы, фото редакторы) показывают ошибку типа кончилось Z>>место и некоторые даже сразу запускают какой-нибудь системный диалог для удаления ненужных файлов.
vsb>Я про серверный софт пишу всё это время.
А какая разница? Так или иначе весь серверный код взаимодействует пользователю,
из-за того что условный Photoshop открывается с помощью загрузки сайта, а не через запуск exe что-то измениться?
Мне кажется как раз наоборот, если раньше при ошибке о недостатка памяти можно было просто упасть,
теперь лучше сообщить об этом пользователю, ведь это реальные деньги: "памяти не хватает для обратки операции XYZ,
оплатите переходите на тариф "ПРО" за +100$ и объем доступной памяти будет увеличен вдвое".
Re[2]: Почему в расте отсутствует выброс исключений?
Здравствуйте, SkyDance, Вы писали:
SD>Оно так было с большинством языков — исключения появились через N итераций.
Не уверен, что это правда, особенно если брать что-то посвежее джавы. По моему исключения в множестве языков были изначально. А уже если на совсем свежие посмотреть, такие как Swift, Go и Rust, то что-то пока исключений не видно. И ладно раст, про него ещё можно сказать, что раз не мейнстрим, то семь лет — это ещё мало, но Go и Swift вполне активно используются. И что-то пока исключений не завезли.
Кстати, в Swift, как по мне, худшее из двух миров: у них там ошибки называются исключениями, но по факту это именно аналог растовых резалтов. В итоге и код зашумляется try, которые надо писать перед каждой функцией, которая можно возвращать ошибку, и в сигнатурах не понятно, что именно за ошибки.
Re[17]: Почему в расте отсутствует выброс исключений?
Здравствуйте, Zhendos, Вы писали:
Z>Для этого не нужно взламывать сервер, конечно пользователю показываются Z>ошибки которые он может исправить: ввести логин и пароль, загрузить другой файл, Z>предоставить правильную ссылку и так далее.
Такие ошибки вообще не должны кидать исключения ни на каком этапе. Неправильный логин — селект возвращает null (или optional для эстетов), код простым if-ов разбирается с ситуацией. То же с паролем и тд. Конечно иногда API нужного просто нет, например в жаве нельзя распарсить строку в число без обработки исключения, но это уже недостаток API. Ряд API было бы неплохо дублировать для двух юз-кейсов. К примеру я в своих программах при работе с базой различаю методы find, которые всегда возвращают один результат, а если результатов 0 или 2+, то кидают исключение и методы query, которые возвращаю Optional. В итоге в коде я либо использую метод find без каких-то дополнительных проверок (к примеру если в URL-е пришёл ID, зачем его проверять, URL это не поддерживаемый элемент интерфейса и ввод кривого URL-а просто приведёт к выбросу этого исключения и возврату его в итоге как 404 страницы), либо метод query, если это уже нормальная форма поиска, к примеру.
Z>А какая разница? Так или иначе весь серверный код взаимодействует пользователю, Z>из-за того что условный Photoshop открывается с помощью загрузки сайта, а не через запуск exe что-то измениться? Z>Мне кажется как раз наоборот, если раньше при ошибке о недостатка памяти можно было просто упасть, Z>теперь лучше сообщить об этом пользователю, ведь это реальные деньги: "памяти не хватает для обратки операции XYZ, Z>оплатите переходите на тариф "ПРО" за +100$ и объем доступной памяти будет увеличен вдвое".
Разница в том, что пользователь в случае с серверным софтом не может ничего исправить. Ну про тарифы про не знаю, с таким не сталкивался. В любом случае это очень точечные обработки ошибок, ради которых по всему коду их обрабатывать — избыточно.
Re[3]: Почему в расте отсутствует выброс исключений?
Здравствуйте, DarkEld3r, Вы писали:
DE>Не уверен, что это правда, особенно если брать что-то посвежее джавы. По моему исключения в множестве языков были изначально. А уже если на совсем свежие посмотреть, такие как Swift, Go и Rust, то что-то пока исключений не видно. И ладно раст, про него ещё можно сказать, что раз не мейнстрим, то семь лет — это ещё мало, но Go и Swift вполне активно используются. И что-то пока исключений не завезли.
Swift это про совместимость с кучей Objective C кода и API, которые никто никогда переписывать не будет.
Go — ну вот исключения это единственное, чего мне не хватает, чтобы объявить его идеальным вариантом для меня.
Rust — системный язык, я полагаю, что исключения для системного языка это спорная технология.
Проблема создания языка очень высокого уровня с GC и подобным в том, что питон и C# уже существуют. Всё остальное — спектрум между ними и не совсем понятно, что тут можно вообще придумать.
Лично мне хотелось бы видеть Rust-подобный язык с исключениями, GC и зелёными потоками. Без ownership-а. Мне в Rust нравится очень много. Но бэкэнд я на нём писать не буду. Я в курсе, что ownership используется не только для памяти, но и для потокобезопасного кода и тд, но мне это никогда не было нужно, поэтому я не слишком убеждён.
А вообще, честно говоря, мне надо просто написать свой фреймворк для Java и успокоиться ) По-сути мне в Java не нравятся только жирнющие фреймворки и небольшие недостатки языка, которые можно потерпеть.
Re[4]: Почему в расте отсутствует выброс исключений?
Здравствуйте, vsb, Вы писали:
vsb>Swift это про совместимость с кучей Objective C кода и API, которые никто никогда переписывать не будет.
B Objective-C исключения вполне есть.
vsb>Проблема создания языка очень высокого уровня с GC и подобным в том, что питон и C# уже существуют. Всё остальное — спектрум между ними и не совсем понятно, что тут можно вообще придумать.
Ну так-то когда придумывали C#, то джава уже существовала, но языки продолжают появляться. Вон Kotlin вполне себе взлетел. В вебе тайпскрипт, вроде как, стал весьма популярен. А вообще всякое интересное регулярно придумывают, правда стать мейнстримом у этого шансов весьма мало.
vsb>Лично мне хотелось бы видеть Rust-подобный язык с исключениями, GC и зелёными потоками. Без ownership-а.
Так что тогда останется от языка? По моему всё остальное уже в том или ином виде уже где-то есть.
Re[5]: Почему в расте отсутствует выброс исключений?
Здравствуйте, DarkEld3r, Вы писали:
vsb>>Swift это про совместимость с кучей Objective C кода и API, которые никто никогда переписывать не будет.
DE>B Objective-C исключения вполне есть.
В эппловых фреймворках везде используется возврат ошибки через NSError**. Я может ошибаюсь, но я не припомню ни одного места, где я бы использовал исключения в Objective C.
vsb>>Проблема создания языка очень высокого уровня с GC и подобным в том, что питон и C# уже существуют. Всё остальное — спектрум между ними и не совсем понятно, что тут можно вообще придумать.
DE>Ну так-то когда придумывали C#, то джава уже существовала, но языки продолжают появляться. Вон Kotlin вполне себе взлетел. В вебе тайпскрипт, вроде как, стал весьма популярен. А вообще всякое интересное регулярно придумывают, правда стать мейнстримом у этого шансов весьма мало.
Смысл в том, что питон это как некий нижний деноминатор для новичков и C# как язык, где есть вообще всё на свете. Kotlin придумывали, когда Java загнивала. С тех пор на бэкэнде у котлина, имхо, будущего нет. Ну гугл на андроид его протащила, да, по каким-то своим причинам. Пока андроид существует, с котлином нормально всё будет.
Тайпскрипт тоже паразитирует на JS. Самостоятельности у него нет.
Да, интересное придумывают, но оно — такое, пытается заполнить какие-то ниши, а не полноценная платформа общего назначения вроде того же .NET. Из последнего только Go, наверное. Ну он, конечно, уникальный.
vsb>>Лично мне хотелось бы видеть Rust-подобный язык с исключениями, GC и зелёными потоками. Без ownership-а.
DE>Так что тогда останется от языка? По моему всё остальное уже в том или ином виде уже где-то есть.
В языке куча приятных конструкций. Банально синтаксис мне нравится. Шаблоны, ООП без классов, макросы хорошие. Ну да, в том или ином виде есть, а так, чтобы было всё приятно — я не видел. Везде какие-то нагромождения лигаси или спорных решений. Да банально snake_case. Уж извините, но мне он нравится, как бы глупо это ни звучало. Я же не буду на Java писать так, меня не поймут. В расте мне всё нравится, кроме ownership (последнее — не то, чтобы не нравилось, идея-то крутая, просто мне оно не надо, GC удобней, рассуждения примерно того же уровня, что и исключения против возврата ошибок).
Re[10]: Почему в расте отсутствует выброс исключений?
Здравствуйте, vsb, Вы писали:
_>>Твоя фраза подразумевает, что при обработке с исключениями не надо писать какой-то код, который надо писать при обработке ошибок через Result в Rust'e. И т.к. это очевидно не код самой реакции на ошибку (который естественно надо писать в любом подходе и языке), то тогда о чём собственно речь? Или ты считаешь "дополнительным кодом" несколько знаков вопроса? vsb>Ну смотри. Может я в расте что-то не понимаю. vsb>Во-первых у каждой функции с ошибками надо возвращать Result вместо конкретного типа. Это как минимум синтаксический шум.
Это ясное выражение в коде того факта, что функция может сгенерировать ошибку. Ведь далеко не все функции такие, есть множество с гарантированным выполнением. Хотя в языке с исключениями об этом факте сложно судить.
vsb>Во-вторых если функция сейчас не бросает ошибок, а завтра начинает бросать, мне надо менять её тип, потом проходить по всем местам её использования и как минимум добавлять туда этот самый вопросик. Потенциально надо рекурсивно менять тип этой вызывающий функции и так далее.
Это как раз максимально удобно, потому что тут тебе IDE сама покажет место, куда необходимо вставить обработчик ошибок. Ведь для ошибок (а не критических ситуаций, которые обрабатываются паниками) как раз характерна обработка по месту, а не один глобальный обработчик на всё приложение.
vsb>В-третьих — да, вопрос это дополнительный код с не такой уж и тривиальной логикой. И один символ тут не должен вводить в заблуждение.
Если ты имеешь в виду ассемблер, то как бы он и в языках с исключениями имеется (слышал про про формирование фрейма исключений?), просто его вставляет компилятор автоматически. И кстати это одна из известных проблем оптимизации, в том смысле что в большинстве языков нет способа сказать компилятору что данная функция точно ничего не бросает (и соответственно тут можно многое оптимизировать). В C++ для этого даже пришлось вводить отдельное ключевое слово! )
vsb>В-четвёртых можно пример, как будет выглядеть код аналогичный vsb>
vsb>есть у меня подозрение, что вопросиком тут не отделаешься. Конечно на выходе нужен именно результат над списком чисел, а не список результатов над числами.
На это тебе уже тут подробно ответили. )
_>>Именно! И как раз для таких ситуаций исключения (или паники) подходят идеально. vsb>Насчёт исключений — хз. В жаве есть какой-то флажок, который при первом же OOM-е просто завершает процесс вместо выбрасывания исключения (и вроде хипдамп пишет). Вот это правильный подход и если бы мне не было лень это прописывать, я бы его прописывал.
Это и есть образцовая паника. )))
_>>Ну тут есть довольно простой ответ, через встречный вопрос. ))) Вот допустим ты используешь механизм исключений для обработки обычных ошибок. Можешь ли ты взяв произвольную функцию в коде точно перечислить список ошибок, который она может вернуть? vsb>Нет, конечно (ну если не считать throws, который был плохой идеей). vsb>Но зачем? Всё, что я знаю — что он может кинуть Exception. Если мне нужно что-то более конкретное — я пойду в нужное место и посмотрю.
В какое такое нужное место? В документацию на функцию из библиотеки? Ну допустим там могут (и то далеко не всегда такое можно увидеть в описание функции) перечислить свои родные исключения. А они точно перечислят ещё и все возможные исключения чужого кода (включая стандартную библиотеку), вызовы которого есть внутри вызова их функции?
vsb>В Java придумали throws в своё время который как раз позволяет типы выбрасываемых исключений добавлять в сигнатуру функции. Но это оказалось плохой идеей и сейчас эту фичу стараются избегать.
Ну вот ты можешь рассматривать сигнатуру функции с Result в Rust, как функцию в Java с использование throws. Но есть два отличающихся нюанса, которые полностью меняют всю картину:
1. В Java данная фича является опциональной, а не обязательной что на корню режет идею о любых гарантиях. Т.е. в таком виде это действительно бесполезное действо, только отнимающее время.
2. В Java нет требования сводить все исключения, бросаемые функцией, к одному типу (пусть даже и максимально абстрактному базовому типу), так что в итоге оператор throws мог выглядеть ужасно (огромным списком из разных иерархий). В Rust'е же это всегда один тип (хотя это может быть и спец. контейнер, который может хранить произвольные типы других ошибок), так что всегда имеет лаконичный код и удобную обработку (через сопоставление с образцом).
Re[16]: Почему в расте отсутствует выброс исключений?
Здравствуйте, vsb, Вы писали:
Z>>И большинство софта с которым я работаю в общем-то "популярные" ошибки пользователя так и обрабатываются как я указал в исходном сообщении. Z>>Если пришел код 401/403 по HTTP то почти любое приложение умеет преобразовать его в диалог повторного Z>>запроса логина и пароля vsb>Вот это как раз и делается очень удобно с исключениями. Заводится одно исключение UnauthorizedException которое может бросить кто угодно и которое на уровне общего обработчика преобразуется в соответствующий HTTP-код.
Интересно чем этот текст отличается от:
Заводится один тип ошибки UnauthorizedException, который может вернуть кто угодно и который на уровне общего обработчика преобразуется в соответствующий HTTP-код?
Т.е. чем по твоему "throw UnauthorizedException()" удобнее чем "return Err(UnauthorizedException())"?
Re[18]: Почему в расте отсутствует выброс исключений?
Здравствуйте, vsb, Вы писали:
Z>>Для этого не нужно взламывать сервер, конечно пользователю показываются Z>>ошибки которые он может исправить: ввести логин и пароль, загрузить другой файл, Z>>предоставить правильную ссылку и так далее. vsb>Такие ошибки вообще не должны кидать исключения ни на каком этапе. Неправильный логин — селект возвращает null (или optional для эстетов), код простым if-ов разбирается с ситуацией. То же с паролем и тд. Конечно иногда API нужного просто нет, например в жаве нельзя распарсить строку в число без обработки исключения, но это уже недостаток API. Ряд API было бы неплохо дублировать для двух юз-кейсов. К примеру я в своих программах при работе с базой различаю методы find, которые всегда возвращают один результат, а если результатов 0 или 2+, то кидают исключение и методы query, которые возвращаю Optional. В итоге в коде я либо использую метод find без каких-то дополнительных проверок (к примеру если в URL-е пришёл ID, зачем его проверять, URL это не поддерживаемый элемент интерфейса и ввод кривого URL-а просто приведёт к выбросу этого исключения и возврату его в итоге как 404 страницы), либо метод query, если это уже нормальная форма поиска, к примеру.
Интересно, что по ходу дискуссии ты стал высказывать тезисы на 100% совпадающие с моим изначальным посылом. Хотя в начале вроде как спорил с ним...
Re[3]: Почему в расте отсутствует выброс исключений?
DE> По моему исключения в множестве языков были изначально.
У меня противоположные ощущения, почти всегда (кроме Java) они были добавлены на том или ином этапе. Обычно через десяток лет. Совсем уж юным языкам, тем же Swift/Go, пока только предстоит. Возможно, конечно, там предусмотрят что-то, называющееся иначе. Но с теми же свойствами: non-local return с автоматическим сбором данных по пути от места выброса до места обработки.
Re[11]: Почему в расте отсутствует выброс исключений?
_>Это как раз максимально удобно, потому что тут тебе IDE сама покажет место, куда необходимо вставить обработчик ошибок. Ведь для ошибок (а не критических ситуаций, которые обрабатываются паниками) как раз характерна обработка по месту, а не один глобальный обработчик на всё приложение.
Вообще-то, в большинстве случаев ошибки обработать можно не "по месту" (где функция вызвана), а где-то десятком уровней выше по стеку. Для этого и нужны исключения, чтобы иметь возможность обработать ошибку не там, где она возникла, а там, где имеется достаточно информации для ее обработки.
Как правило, непосредственный caller не имеет эту информацию, поэтому тоже вынужден вернуть ошибку, и далее по курсу (см. "bubble wrapping", видимо, мне пора уже начать публиковать все внутренние статьи, что я писал за годы, и объяснял, что bubble wrapping в итоге почти всегда превращается в самодельные exceptions).
Re[4]: Почему в расте отсутствует выброс исключений?
Здравствуйте, SkyDance, Вы писали:
SD>У меня противоположные ощущения, почти всегда (кроме Java) они были добавлены на том или ином этапе.
Хаскелисты наоборот до сих пор жалеют что с дуру добавили исключения, но выпилить их уже не могут.
В раст просто унаследовали хаскелевское заболевание головного мозга что ошибки всегда должны выражаться в типах
Здравствуйте, SkyDance, Вы писали:
SD>У меня противоположные ощущения, почти всегда (кроме Java) они были добавлены на том или ином этапе. Обычно через десяток лет.
В C# 1.0 разве не было исключений?.. В питоне исключения были ещё до версии 1.0, если я правильно понимаю. В Ruby, вроде, тоже, как и в Objective-C. Впрочем, не со всеми из этих языков я близко знаком и где-то мог ошибиться, но быстрое гугление подтверждает.
Даже с С++ не всё так просто. Да, формально от первого упоминания языка до появления исключений прошло дофига времени, но так-то в первом стандарте они уже были. Кстати, мне кажется, что у новых языков такой фокус не пройдёт: если у языка нет какой-то "киллер фичи", ну или сильной поддержки от корпорации (в идеале монополиста на платформе), то выкатить что-то сырое, а потом десять лет добавлять базовые вещи не получится.
SD>Совсем уж юным языкам, тем же Swift/Go, пока только предстоит.
Поживём увидим.
Re[5]: Почему в расте отсутствует выброс исключений?
FR>Хаскелисты наоборот до сих пор жалеют что с дуру добавили исключения, но выпилить их уже не могут.
Хехе
Вариантов-то всего два, либо есть checked exception(s), либо нет. Если они есть, приходится везде explicitly добавлять что-то вроде ? (Rust), maybe (Erlang), with (Elixir) и прочие варианты.
Если нет, то "что-то может быть где-то implicitly, и этого не будет видно". И так плохо, и этак. Так что варианта по сути два: либо добавлять exceptions в язык, либо делать их поверх (путем создания всяких там Result<Success,Error>, {ok, Result} | {error, Reason}, и т.п.).
Лично мне нравятся exceptions, просто потому что кода меньше. Но я также понимаю тех, кто хотят explicit mention что функция может стрельнуть. Оно удобно, особенно в хорошо изолированных проектах. Но когда попадаешь в гигантский монолит из легаси-спагетти, еще и работающего на распределенном кластере, там практически каждый вызов имеет этот maybe/with/?.
Re[12]: Почему в расте отсутствует выброс исключений?
Здравствуйте, SkyDance, Вы писали:
_>>Это как раз максимально удобно, потому что тут тебе IDE сама покажет место, куда необходимо вставить обработчик ошибок. Ведь для ошибок (а не критических ситуаций, которые обрабатываются паниками) как раз характерна обработка по месту, а не один глобальный обработчик на всё приложение. SD>Вообще-то, в большинстве случаев ошибки обработать можно не "по месту" (где функция вызвана), а где-то десятком уровней выше по стеку. Для этого и нужны исключения, чтобы иметь возможность обработать ошибку не там, где она возникла, а там, где имеется достаточно информации для ее обработки.
Конечная обработка (в смысле показа сообщения пользователю) действительно обычно происходит где-то на несколько уровней выше точки возникновения ошибки. Но нюанс в том, что для нормальной обработки (показа информативного сообщения и т.п.) необходимо собрать контекстную информацию на почти каждом промежуточном уровне. Т.е. по сути если делаешь на исключениях, то надо их ловить вокруг каждого вызова функции и далее выбрасывать новое (с добавленной информацией этого уровня). Именно это я имел в виду, когда говорил о необходимости обработки по месту.
В Rust'е в принципе всё тоже самое, но есть пара нюансов. Во-первых в нём невозможно пропустить эту самую обработку (если достаточно перенаправить ошибку выше без всяких контекстов, то просто ставишь оператор "знак вопроса" в этой точке, но при этом ты явно видишь что здесь возможно возникновение ошибки и все возможные её типы). А во-вторых развиты средства её автоматизации (выглядит это например так https://docs.rs/anyhow/latest/anyhow/).
Re[13]: Почему в расте отсутствует выброс исключений?
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, SkyDance, Вы писали:
_>В Rust'е в принципе всё тоже самое, но есть пара нюансов. Во-первых в нём невозможно пропустить эту самую обработку (если достаточно перенаправить ошибку выше без всяких контекстов, то просто ставишь оператор "знак вопроса" в этой точке, но при этом ты явно видишь что здесь возможно возникновение ошибки и все возможные её типы). А во-вторых развиты средства её автоматизации (выглядит это например так https://docs.rs/anyhow/latest/anyhow/).
Думаю одно из самых важных средств при проталкивании ошибки вверх это context(), добавляя описания что собственно собирались сделать. И вместо "error opening file" где то сверху ты получаешь что то типа:
Error: Failed to read instrs from ./path/to/instrs.json
Caused by:
No such file or directory (os error 2)
Re[13]: Почему в расте отсутствует выброс исключений?
_>В Rust'е в принципе всё тоже самое, но есть пара нюансов. Во-первых в нём невозможно пропустить эту самую обработку (если достаточно перенаправить ошибку выше без всяких контекстов, то просто ставишь оператор "знак вопроса" в этой точке, но при этом ты явно видишь что здесь возможно возникновение ошибки и все возможные её типы)
В большинстве случаев нужен как раз тот самый "знак вопроса". Поэтому многие языки именно его и имеют по умолчанию. Дабы снизить количество boilerplate. И выражать только конкретное намерение (intent) добавить некий контекст к пролетающему исключению. Там где нечего добавить — ничего и писать не надо. Потому этот знак вопроса лишний.
vaa>Почему в расте отсутствует выброс исключений? Это же удобный способ передачи управления.
Очень хорошая статья по ссылкам.
I suspect that most members of the C++ community vastly underestimate the skills needed to program with exceptions and therefore underestimate the true costs of their use. The popular belief is that exceptions provide a straightforward mechanism for adding reliable error handling to our programs. On the contrary, I see exceptions as a mechanism that may cause more ills than it cures. Without extraordinary care, the addition of exceptions to most software is likely to diminish overall reliability and impede the software development process.
This “extraordinary care” demanded by exceptions originates in the subtle interactions among language features that can arise in exception handling. Counter-intuitively, the hard part of coding exceptions is not the explicit throws and catches. The really hard part of using exceptions is to write all the intervening code in such a way that an arbitrary exception can propagate from its throw site to its handler, arriving safely and without damaging other parts of the program along the way.