Обработка ошибок

Akupaka

А че я?.. О.о
04.10.2007
3 360
1
#1
Всем привет.

Пытаюсь тут наваять принципы обработки ошибок и обработчики поинтереснее придумать под LS.
Возник вопрос, а можно ли определить, что ошибка возникла в текущей процедуре, а не в вызванной из нее?
Понятно, что можно для каждой вызываемой процедуры объявить свой обработчик, ну, а без такового можно?

Кому интересно, из практики:
- результат функции не инициализируется, если в ней возникла необработанная исключительная ситуация, даже, если перед ее возникновением этот результат был назначен.
Т.е.:
Код:
Function F1() As Variant
F1 = False
Error 1000, "Some error"
End Function

Sub Initialize()
' так использовать нельзя
On Error Resume Next
If F1() Then
Msgbox "F1 returned True"
End If

' так лучше
Dim F1Res as Variant
On Error Resume Next
F1Res = F1()
If F1Res Then
Msgbox "F1 returned True"
End If

' причем, если F1Res используется для возврата значений нескольких функций, то перед вызовом функции ее (F1Res) необходимо сбрасывать!
Dim F2Res as Variant
On Error Resume Next
F2Res = True
F2Res = F1() ' F1() не вернула результат, но и не сбросила состояние F2Res!!! F2Res == True из предыдущего состояния
If F2Res Then
' ЭТОТ код выполнится ошибочно
Msgbox "F1 returned True"
End If
End Sub
Для решения этой проблемы, нужно иметь в функции обязательный обработчик, в котором происходит инициализация возвращаемого значения, при этом, ошибку необходимо передавать либо в результате, либо в иной структуре (возвращаемый параметр, глобальная переменная/объект).
 

ToxaRat

Чёрный маг
Lotus team
06.11.2007
3 233
18
#2
юзай GetThreadInfo
Код:
Code	Meaning
LSI_THREAD_LINE	Current Line Number 
LSI_THREAD_PROC	Name of current procedure
LSI_THREAD_MODULE	Name of current module
LSI_THREAD_VERSION	LotusScript version number
LSI_THREAD_LANGUAGE	(Human) language setting
LSI_THREAD_COUNTRY	Country or region setting
LSI_THREAD_TICKS	Get current clock ticks
LSI_THREAD_TICKS_PER_SEC	Get clock ticks per second (supported only on platforms that support parallel processing primitives)
LSI_THREAD_PROCESS_ID	Get current process ID (supported only on platforms that support parallel processing primitives)
LSI_THREAD_TASK_ID	Get current task ID (supported only on platforms that support parallel processing primitives)
LSI_THREAD_CALLPROC	Get the name of the calling procedure
LSI_THREAD_CALLMODULE	Get the name of the calling module
для обработки ошибок самое оно
 

nvyush

Lotus team
22.04.2009
2 317
0
#4
Если лень объявлять обработчики в вызываемых процедурах, то можно, конечно, и такое сваять:
Код:
Sub Test()
On Error Goto Err1
Call Sub1()
On Error Goto Err2
Call Sub2()
On Error Goto Errh
ExitProc:
Exit Sub
Err1:
Msgbox "Error call Sub1"
Resume ExitProc
Err2:
Msgbox "Error call Sub2"
Resume ExitProc
Errh:
Msgbox "Error in Test"
Resume ExitProc
End Sub
Я предпочитаю объявлять обработчики ошибок явно во всех вызываемых процедурах/функциях в стиле http://www.ferdychristant.com/blog//articles/DOMM-6BPT8R
P.S. Ни разу не удалось трассировкой вызовов уронить Лотус.
 

nvyush

Lotus team
22.04.2009
2 317
0
#6
Може я особенный? :) На каком-то из N-уровней вложенности у меня стабильно валился клиент. Был какой-то из 6/7 нотесов.
Где-то натыкался на информацию, что недокументированная функция Lsi_info не является thread-safe, т.е. если её дёргают несколько потоков, то можно уронить клиента/сервера. Особенно актуально для сервера. Поэтому лучше использовать GetThreadInfo.

P.S. Тут обсуждалось: http://www-10.lotus.com/ldd/nd6forum.nsf/C...3c?OpenDocument
 

Omh

Lotus team
04.07.2007
2 210
1
#7
Я поступаю так же как nvy, обработчик ошибок в каждой процедуре/ф-ии локальный (т.е. не возвращает ошибку наверх).
 
13.03.2009
625
1
#8
- результат функции не инициализируется, если в ней возникла необработанная исключительная ситуация, даже, если перед ее возникновением этот результат был назначен.
и рыпку съесть и .... :)
хочеца одновременно и значение вернуть и исключение бросить? так не бывает :)
про getthreadinfo: можно смело использовать константы, объявленные в хелпе.
по теме есть классика от A. Guirard: http://www.ibm.com/developerworks/lotus/li...gLS2/index.html
Еще один вариант хэндлера попадался недавно в шаблоне discussion 8.5. (lslib)lsClassException.
 

Akupaka

А че я?.. О.о
04.10.2007
3 360
1
#9
Я поступаю так же как nvy, обработчик ошибок в каждой процедуре/ф-ии локальный (т.е. не возвращает ошибку наверх).
А он разве так делает? :) Если он делает так же как в статье, то там обработка ошибок поднимается наверх, но с трейсом.

nvy
Если я правильно помню, то я записывал значения из GetThreadInfo (но не помню точно или из LSI_info) в свой массив! Т.е. не так как в статье.
Так как в статье я тоже делаю обычно, только по-своему группирую. Но в случае с функциями так делать нельзя, почему писал выше.

Добавлено:
хочеца одновременно и значение вернуть и исключение бросить? так не бывает :)
Бывает, но надо немного допилить :) т.е. исключение "поднять" в вызывающей функции. Т.е. как в лотусе часто бывает - через жп.
 

nvyush

Lotus team
22.04.2009
2 317
0
#10
Я поступаю так же как nvy, обработчик ошибок в каждой процедуре/ф-ии локальный (т.е. не возвращает ошибку наверх).
Не, я поступаю не так. В библиотеках обработчик ошибки возвращает ошибку наверх, а вот в кнопках и событиях ошибки обрабатываются и логируются. В результате всегда (почти) можно посмотреть, откуда у ошибки "ноги растут".

Добавлено:
Но в случае с функциями так делать нельзя, почему писал выше.
При возникновении ошибки в функции возможны два подхода. Либо функция генерит ошибку и не возвращает ничего вразумительного, либо внутри себя сбрасывает ошибку и возвращает Null, Nothing, Empty, False и т.д. Это к вопросу об использовании конструкцци On Error Resume Next — её использование оправдано в исключительных случаях (и побольшей части из-за лени программиста нормально обработать ошибки).
 

Omh

Lotus team
04.07.2007
2 210
1
#11
Ну, значит, так как nvy, но ошибку наверх не возвращаю.
Другими словами, не так :) :)

Чёт я слажал немного :)
Смотрю в книгу, вижу фигу.
 

Medevic

Что это ? :)
Lotus team
10.12.2004
3 346
1
#12
При возникновении ошибки в функции возможны два подхода. Либо функция генерит ошибку и не возвращает ничего вразумительного, либо внутри себя сбрасывает ошибку и возвращает Null, Nothing, Empty, False и т.д. Это к вопросу об использовании конструкцци On Error Resume Next — её использование оправдано в исключительных случаях (и побольшей части из-за лени программиста нормально обработать ошибки).
Да можно и ошибку вернуть и значение. Только зачем?
 
13.03.2009
625
1
#14
Бывает, но надо немного допилить ;) т.е. исключение "поднять" в вызывающей функции. Т.е. как в лотусе часто бывает - через жп.
Это не через жп. Это подход, принятый в цивилизованных языках, поддерживающих исключения. Если функция бросила исключение - она не возвращает результата. Грубо говоря - она возвращает объект исключения.
Да можно и ошибку вернуть и значение.
Ниче не понимаю... Если функция бросает исключение - она ничего не возвращает. Или не так? Можно конечно по сишной традиции возвращать код ошибки, а значение возвращать через входной параметр функции. Но речь вроде идет именно об исключениях?
 

Мыш

Lotus team
12.02.2008
1 099
10
#16
А если ошибка возникает уже в обработчике ошибки? Скажем, обработчик уже произошедшей ошибки хочет отправить сообщение по почте, создать документ в базе, зачистить какие-то файлы на уровне ОС и т.п. - и вновь вызывает ошибку. Я в таких случаях пишу "... resume next"...
 
13.03.2009
625
1
#17
Да? Значит я думаю через жп ))
Меня бы лично такое поведение(значение + exception) повергло в шок:
Пользователь: Компьютер, скока будет дважды два?
Компьютер: Четыре, и, кстати, у тебя канал до сервера отвалился!
Как документировать такую функцию: всегда возвращает верное значение, но иногда при этом бросает ошибку?
Очевидно напрашивается разделение функции на две, каждая из которых будет занимаца своим делом.
 

Medevic

Что это ? :)
Lotus team
10.12.2004
3 346
1
#18
Ниче не понимаю... Если функция бросает исключение - она ничего не возвращает. Или не так? Можно конечно по сишной традиции возвращать код ошибки, а значение возвращать через входной параметр функции. Но речь вроде идет именно об исключениях?
Исключение мы обработаем внутри. Но с помощью Err можно узнать номер ошибки после выхода из функции. И при желании вызвать еще одно исключение.
Короче, пример. В результате получим и 5, и обработаем ошибку.
Код:
Sub test
On Error Goto e
Msgbox(Cstr(errtest))
If Err Then Error Err
Exit Sub
e:
Msgbox Error
Resume
End Sub

Function errtest As Long
On Error Goto e
Dim a As Long, b As Long
b = 1
errtest = 5
errtest = b / 0
Exit Function
e:
Exit Function
End Function
 

Мыш

Lotus team
12.02.2008
1 099
10
#19
В результате получим и 5, и обработаем ошибку.
А какая польза-то от этой пятерки? Она же не есть правильное значение, полученное в результате выполнения функции. Хотя если использовать возвращаемое значение как нумератор строк кода... ;)
 

Medevic

Что это ? :)
Lotus team
10.12.2004
3 346
1
#20
А какая польза-то от этой пятерки? Она же не есть правильное значение, полученное в результате выполнения функции. Хотя если использовать возвращаемое значение как нумератор строк кода... ;)
Да хз. Я таким не пользуюсь. :)