Существует множество требований, необходимых для правильной передачи и обработки исключений системой. Существует также много вариантов выбора языка для реализации концепции.
Требования к исключениям (в произвольном порядке):
Документирование : язык должен иметь возможность документировать исключения, которые может генерировать API. В идеале этот носитель документации должен быть пригоден для использования машиной, чтобы компиляторы и IDE могли оказывать поддержку программисту.
Передача исключительных ситуаций : эта ситуация очевидна, чтобы позволить функции передавать ситуации, которые мешают вызываемой функциональности выполнить ожидаемое действие. На мой взгляд, есть три большие категории таких ситуаций:
2.1 Ошибки в коде, которые приводят к тому, что некоторые данные являются недействительными.
2.2 Проблемы с настройкой или другими внешними ресурсами.
2.3 Ресурсы, которые по своей природе ненадежны (сеть, файловые системы, базы данных, конечные пользователи и т. Д.). Это небольшой случай, так как их ненадежный характер заставляет нас ожидать их спорадических неудач. В этом случае эти ситуации следует считать исключительными?
Предоставьте достаточно информации для кода, чтобы справиться с ним : Исключения должны предоставлять достаточную информацию для вызываемого, чтобы он мог реагировать и, возможно, справляться с ситуацией. информация также должна быть достаточной, чтобы при регистрации эти исключения обеспечили программисту достаточный контекст, чтобы идентифицировать и изолировать ошибочные операторы и предоставить решение.
Обеспечить уверенность программиста в текущем состоянии состояния выполнения его кода : возможности обработки исключений в программной системе должны присутствовать достаточно, чтобы обеспечить необходимые меры безопасности, оставаясь в стороне от программиста, чтобы он мог сосредоточиться на задаче в рука.
Чтобы покрыть это, были реализованы следующие методы на разных языках:
Проверенные исключения Обеспечивают отличный способ документировать исключения, и теоретически при правильной реализации должны обеспечивать достаточную уверенность в том, что все в порядке. Однако стоимость такова, что многие считают более продуктивным просто обходить либо проглатывая исключения, либо перебрасывать их как непроверенные исключения. При ненадлежащим образом проверенных исключениях все это теряет свою полезность. Кроме того, проверенные исключения затрудняют создание API, стабильного во времени. Реализации универсальной системы в конкретном домене принесут массу исключительных ситуаций, которые будет сложно поддерживать с использованием исключительно проверенных исключений.
Непроверенные исключения - гораздо более универсальные, чем проверенные исключения, они не могут должным образом документировать возможные исключительные ситуации данной реализации. Они полагаются на специальную документацию, если вообще. Это создает ситуации, когда ненадежный характер среды маскируется API, который создает видимость надежности. Кроме того, когда эти исключения выбрасываются, они теряют свое значение по мере продвижения вверх через уровни абстракции. Так как они плохо документированы, программист не может нацеливаться на них конкретно, и ему часто приходится создавать гораздо более широкую сеть, чем необходимо, чтобы вторичные системы, если они выйдут из строя, не сломали всю систему. Что возвращает нас к проблеме глотания проверенных исключений.
Типы возвращаемых данных с несколькими состояниями Здесь необходимо полагаться на непересекающийся набор, кортеж или другую подобную концепцию для возврата ожидаемого результата или объекта, представляющего исключение. Здесь нет разматывания стека, нет вырезки кода, все выполняется нормально, но возвращаемое значение должно быть проверено на наличие ошибок перед продолжением. На самом деле я еще не работал с этим, поэтому не могу прокомментировать из своего опыта. Я признаю, что он разрешает некоторые проблемы, исключая обход нормального потока, но все же он будет страдать от тех же проблем, что и проверенные исключения, так как он утомителен и постоянно "перед вами".
Итак, вопрос:
Каков ваш опыт в этом вопросе и что, по вашему мнению, является лучшим кандидатом для создания хорошей системы обработки исключений для языка?
РЕДАКТИРОВАТЬ: Через несколько минут после написания этого вопроса я наткнулся на этот пост , жуткий!
источник
noexcept
истории на C ++ может дать очень хорошее представление о EH в C # и Java.)Ответы:
В первые дни C ++ мы обнаружили, что без какого-либо общего программирования языки со строгой типизацией были бы чрезвычайно громоздкими. Мы также обнаружили, что проверенные исключения и общее программирование не работали вместе, и проверенные исключения были по существу заброшены.
Типы возврата Multiset хороши, но не заменит исключения. Без исключений, код полон проверочного шума.
Другая проблема с проверенными исключениями состоит в том, что изменение в исключениях, генерируемых функцией низкого уровня, вызывает каскад изменений во всех вызывающих, их вызывающих и т. Д. Единственный способ предотвратить это - для каждого уровня кода перехватывать любые исключения, создаваемые более низкими уровнями, и заключать их в новое исключение. Опять же, вы получите очень шумный код.
источник
В течение долгого времени в ОО-языках использование исключений являлось стандартом де-факто для сообщения об ошибках. Но функциональные языки программирования предоставляют возможность другого подхода, например, использование монад (которые я не использовал) или более легкое «железнодорожное программирование», как описано Скоттом Влащиным.
В этом блоге
В этой презентации на НДЦ 2014
Это действительно вариант многогосударственного типа результата.
Тип результата может быть объявлен так
Таким образом , в результате функции , которая возвращает этот тип будет либо
Success
илиFail
типа. Это не может быть и то и другое.В более императивно-ориентированных языках программирования этот стиль может потребовать большого количества кода на сайте вызывающей стороны. Но функциональное программирование позволяет вам создавать связывающие функции или операторы, чтобы связывать воедино несколько функций, чтобы проверка ошибок не занимала половину кода. Например:
updateUser
Вызовы функций каждой из этих функций последовательно, и каждый из них может не сработать. Если все они успешны, возвращается результат последней вызванной функции. В случае сбоя одной из функций, результат этой функции будет результатом всейupdateUser
функции. Все это обрабатывается пользовательским оператором >> =.В приведенном выше примере типы ошибок могут быть
Если вызывающая
updateUser
сторона явно не обрабатывает все возможные ошибки из функции, компилятор выдаст предупреждение. Итак, у вас есть все задокументировано.В Haskell есть
do
нотация, которая может сделать код еще чище.источник
do
нотацию на Haskell , которая делает полученный код еще чище.Railway Oriented Programming
точно монадическое поведение.Я нахожу ответ Пита очень хорошим, и я хотел бы добавить некоторые соображения и один пример. Очень интересная дискуссия относительно использования исключений в сравнении с возвращением специальных значений ошибок может быть найдена в Программировании в Standard ML Робертом Харпером в конце Раздела 29.3, стр. 243, 244.
Проблема заключается в реализации частичной функции,
f
возвращающей значение некоторого типаt
. Одним из решений является использование функции типаи бросить исключение, когда нет возможного результата. Второе решение заключается в реализации функции с типом
и вернуть
SOME v
на успех, иNONE
на провал.Вот текст из книги с небольшой адаптацией, сделанной мной, чтобы сделать текст более общим (книга ссылается на конкретный пример). Измененный текст написан курсивом .
Это касается выбора между исключениями и типами возвращаемых опций.
Что касается идеи, что представление ошибки в возвращаемом типе приводит к проверке ошибок, распространяющейся по всему коду: это не должно иметь место. Вот небольшой пример в Haskell, который иллюстрирует это.
Предположим, мы хотим проанализировать два числа, а затем разделить первое на второе. Поэтому может возникнуть ошибка при разборе каждого числа или при делении (деление на ноль). Поэтому мы должны проверять наличие ошибок после каждого шага.
Разбор и деление выполняются в
let ...
блоке. Обратите внимание, что при использованииMaybe
монады иdo
нотации указывается только путь успеха : семантикаMaybe
монады неявно распространяет значение ошибки (Nothing
). Никаких накладных расходов для программиста.источник
Either
тип будет более подходящим. Что вы делаете, если попадаетеNothing
сюда? Вы просто получаете сообщение «ошибка». Не очень полезно для отладки.Я стал большим поклонником Проверенных Исключений, и я хотел бы поделиться своим общим правилом о том, когда их использовать.
Я пришел к выводу, что в основном мой код имеет дело с двумя типами ошибок. Есть ошибки, которые можно проверить перед выполнением кода, и есть ошибки, которые нельзя проверить перед выполнением кода. Простой пример ошибки, которую можно проверить перед выполнением кода в исключении NullPointerException.
Простой тест мог бы избежать ошибки, такой как ...
В вычислительной технике бывают случаи, когда вы можете выполнить 1 или более тестов перед выполнением кода, чтобы убедиться, что вы в безопасности и вы все равно получите исключение. Например, вы можете проверить файловую систему, чтобы убедиться, что на жестком диске достаточно места, прежде чем записывать данные на диск. В многопроцессорной операционной системе, такой как используемая сегодня, ваш процесс может проверить дисковое пространство, и файловая система вернет значение, сообщающее, что места достаточно, а затем переключение контекста на другой процесс может записать оставшиеся байты, доступные для операционной системы. система. Когда контекст операционной системы переключается обратно на ваш работающий процесс, где вы записываете свое содержимое на диск, возникает исключение просто потому, что в файловой системе недостаточно места на диске.
Я рассматриваю сценарий выше как идеальный случай для Проверенного Исключения. Это исключение в коде, которое заставляет вас иметь дело с чем-то плохим, даже если ваш код может быть идеально написан. Если вы решили делать плохие вещи, такие как «проглотить исключение», вы плохой программист. Кстати, я обнаружил случаи, когда разумно проглотить исключение, но, пожалуйста, оставьте комментарий в коде, почему исключение было проглочено. Механизм обработки исключений не виноват. Я часто шучу, что предпочитаю, чтобы мой кардиостимулятор был написан на языке с проверенными исключениями.
Есть моменты, когда становится трудно решить, является ли код тестируемым или нет. Например, если вы пишете интерпретатор и выдается исключение SyntaxException, когда код не выполняется по какой-либо синтаксической причине, должно ли SyntaxException быть проверенным исключением или (в Java) RuntimeException? Я бы ответил, если интерпретатор проверяет синтаксис кода перед его выполнением, тогда Исключение должно быть RuntimeException. Если интерпретатор просто запускает код «горячий» и просто вызывает синтаксическую ошибку, я бы сказал, что исключение должно быть проверенным исключением.
Я признаю, что я не всегда счастлив поймать или выбросить Проверенное Исключение, потому что есть время, когда я не уверен, что делать. Проверенные исключения - это способ заставить программиста помнить о потенциальной проблеме, которая может возникнуть. Одна из причин, по которой я программирую на Java, заключается в том, что в нем есть Проверенные исключения.
источник
В настоящее время я нахожусь в середине довольно большого проекта / API на основе ООП, и я использовал эту схему исключений. Но все зависит от того, насколько глубоко вы хотите использовать обработку исключений и тому подобное.
ExpectedException
- AuthorisedException
- EmptySetException
- NoRemainingException
- NoRowsException
- NotFoundException
- ValidationException
Неожиданное исключение
- ConnectivityException
- EnvironmentException
- ProgrammerException
- SQLException
ПРИМЕР
источник
NAN
илиNULL
.