Разница между ошибками / исключениями и выбросом / уловом?

Меня немного смущает обработка ошибок в Rebol. Имеет конструкции БРОСА и ЗАХВАТА:

>> repeat x 10 [if x = 9 [throw "Nine!"]]
** Throw error: no catch for throw: make error! 2

>> catch [repeat x 10 [if x = 9 [throw "Nine!"]]]
== "Nine!"

Но этот бросок и захват не связаны с обработчиком, переданным в уточнение / EXCEPT в TRY:

>> try/except [throw "Nine!"] [print "Exception handled!"]
** Throw error: no catch for throw: make error! 2

Это очень характерно для типа ошибки Rebol:

>> try/except [print 1 / 0] [print "Error handled!"]
Error handled!

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

>> try/except [throw make error! "Error string"] [print "Error handled!"]
** Throw error: no catch for throw: make error! 2

Вы должны СДЕЛАТЬ их, чтобы оценщик попытался выполнить что-то типа error! вызвать то, что он считает "исключением":

>> try/except [do make error! "Error string"] [print "Error handled!"]
Error handled!

(Примечание: вы можете использовать заранее подготовленные ошибки, очевидно, например cause-error 'Script 'invalid-type function! - подробнее см. system/catalog/errors.)

Если вы не укажете уточнение / EXCEPT, вы сможете получать любые ошибки в качестве значения. Однако это, похоже, делает невозможным различить, была ли вызвана ошибка или нет:

>> probe try [do make error! "Some error"]
make error! [
    code: 800
    type: 'User
    id: 'message
    arg1: "some error"
    arg2: none
    arg3: none
    near: none
    where: none
]
** User error: "Some error"

>> probe try [make error! "Some error"]
make error! [
    code: 800
    type: 'User
    id: 'message
    arg1: "Some error"
    arg2: none
    arg3: none
    near: none
    where: none
]
** User error: "Some error"

Казалось бы, в CATCH такое же отсутствие различий между возвратом значения и выдачей значения. Но есть способ обойти это с помощью «именованных бросков»:

>> code: [repeat x 10 [if x = 9 [throw/name "Nine!" 'number]]]

>> catch/name [do code] 'number
== "Nine!"

>> catch/name [do code] 'somethingelse
** Throw error: no catch for throw: make error! 2

Итак, теперь вопросы:

  • Есть ли практическая ценность в этом разделении? Как решить, использовать ли THROW и CATCH или DO ошибки и обработать это с помощью TRY / EXCEPT?

  • Есть ли у этого различия прецедент в других языках, и было бы лучше назвать / EXCEPT / ON-ERROR или что-то в этом роде?

  • Почему написано "no catch for throw: make error! 2" вместо чего-то более информативного? Что такое make error! 2?


person HostileFork says dont trust SE    schedule 25.06.2014    source источник


Ответы (3)


«Есть ли практическая ценность в этом разделении? Как решить, использовать ли THROW и CATCH или DO ошибки, и обработать это с помощью TRY / EXCEPT?»

Как было указано в других ответах, THROW и CATCH образуют раскручивающуюся конструкцию (нелокальный выход), которая сама по себе связана с потоком управления и не обязательно имеет какое-либо отношение к обработке ошибок. THROW и CATCH - это, прежде всего, простой метод воздействия на поток управления и довольно фундаментальный строительный блок для других пользовательских конструкций потока управления.

Как таковые, THROW и CATCH, конечно, также могут быть использованы для построения системы ошибок, подобной «обработке исключений», как это видно во многих современных основных языках, потому что эти системы «обработки исключений» являются одним из примеров нелокального потока управления.

Rebol error!, с другой стороны, является основным методом сигнализации и распространения ошибок оценки.

В общем, решение легко принять: если вы хотите вызвать ошибку, используйте error!. Если вы хотите повлиять на поток управления для управляемой раскрутки, используйте THROW / CATCH.

Еще два замечания по терминологии:

  • Обсуждение ошибок Rebol стало более осторожным, чтобы использовать выражение «причина ошибки» в качестве фраза вместо «выдать ошибку», чтобы избежать путаницы.
  • Аналогичным образом, необходимо переработать ссылки, которые называют THROW / CATCH «обработкой исключений Rebol» (как @HostileFork ссылается на один комментарий).

«Есть ли у этого различия прецедент в других языках?»

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

"Почему он говорит" нет уловки для throw: сделайте ошибку! 2 "вместо чего-то более информативного? Что за ошибка make! 2?"

Это ошибка. (Хорошая уловка!) Я бы сказал, что суть сообщения об ошибке («no catch for throw») уже довольно информативна, но make error! 2 - это ошибка (здесь скорее должно отображаться выброшенное значение).

"было бы / EXCEPT было бы лучше назвать / ON-ERROR или что-то в этом роде?"

Переименование /EXCEPT спорно. Таким образом, я бы сказал, что это обсуждение не очень подходит для SO Q&A и его лучше оставить на других форумах.

person earl    schedule 26.06.2014


Я не очень хорошо знаком с обработкой ошибок в Rebol, но особенность исключений, генерации и перехвата заключается в том, что они часто рассматриваются как конструкции «обработки ошибок», что является довольно узким понятием. Вместо этого лучше думать о try / catch как о механизме управления потоком. Но в то время как выход из цикла просто приводит к выходу из ближайшего окружающего блока, выгода, которую вы получаете от выброса исключения, заключается в том, что оно может охватить несколько кадров в стеке. Таким образом, вы можете более легко изолировать отдельные блоки кода как логическую единицу, которая, если какая-либо ее часть выходит из строя, может рассматриваться как отказ логической единицы, независимо от того, насколько далеко в стеке возникает исключение.

Извините, возможно, это не ответило на ваш вопрос напрямую, но я подумал, что могу обратиться к вашему второму пункту: следует ли называть его ON-ERROR. Я бы сказал нет, потому что исключение не обязательно означает ошибку; как средство управления потоком это просто более общая инструкция о том, что произошло условие, которое не должно допускать дальнейшего выполнения по определенному пути.

person mydoghasworms    schedule 25.06.2014
comment
В другом комментарии я упомянул, что мне понравилось определение исключение - это когда член не может выполнить задачу, которую он должен выполнять, как указано его именем. В любом случае, я чувствую, что с терминологией нужно разобраться. здесь ... потому что я делал много throw make error! "...", потому что я думал, что это именно то, что вы должны были сделать, и взял на себя ответственность затем проанализировать объект ошибки, напечатать и выйти ... не понимая, что я могу СДЕЛАТЬ ошибка и получите такое же поведение. Он не похож на другие языки и требует более четкого объяснения. - person HostileFork says dont trust SE; 25.06.2014