Код без ошибок – возможно ли?

Коды, которые Вы будете разрабатывать, должны быть не только удобны и обладать приемлемым быстродействием, но и быть безошибочными. Что подразумевается под безошибочностью?
Все достаточно просто: в любом случае, после завершения работы функции (корректного или некорректного - это неважно) AutoCAD должен принять вид, который был установлен пользователем до вызова функции. Логические ошибки типа (/ 50. 0.) отследить просто, но как отследить ошибки пользователя? Например, нажатие [Esc] в самый неподходящий момент?
Есть несколько вариантов.

Вариант 1. Переопределение стандартного обработчика ошибок. В AutoCAD обязательно присутствует штатный обработчик ошибок, и имя ему - *error*. Функция принимает единственный параметр (текстовое сообщение об ошибке). А вот ее "внутренности" уже могут меняться. Так, например, обработчик ошибок в AutoCAD Architecture видоизменен самой Autodesk.
Переопределить обработчик можно - то есть написать собственную функцию *error*, которая будет выполнять те действия, которые требуются. Переопределить *error* можно и глобально (отдельной функцией), и локально - для определенной функции. Пример:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
(defun lispru-func-1 (/ *error* fun_func-2)

  (defun *error* (msg)
    (princ (strcat "\n lispru-func-1 error : " msg))
    (princ)
    ) ;_ end of defun

  (defun fun_func-2 (/ *error*)

    (defun *error* (msg)
      (princ (strcat "\n fun_func-2 error : " msg))
      (princ)
      ) ;_ end of defun

    (princ (/ 10. 0.))
    ) ;_ end of defun

  (princ "\ncall (fun_func-2)")
  (fun_func-2)
  (princ "(fun_func-2) finished")
  (sqrt -1.)
  ) ;_ end of defun

Если попытаться вызвать (lispru-func-1), мы получим в консоли:

1
2
3
4
call (fun_func-2)

 fun_func-2 error : divide by zero
_$

То есть такой обработчик заканчивает выполнение функции - обратите внимание, текст "(fun_func-2) finished" даже не пытается напечататься: срабатывает обработчик, прописанный в fun_func-2, и на этом выполнение кода заканчивается. А если продолжать все равно надо? В таком случае приходит на помощь вариант 2:
Использование функции vl-catch-*:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
(defun lispru-func-2 (/ err fun_func-2)

  (defun fun_func-2 (/ err)

    (if (vl-catch-all-error-p
          (setq err (vl-catch-all-apply
                      (function
                        (lambda ()
                          (princ (vl-princ-to-string (/ 10. 0.)))
                          ) ;_ end of lambda
                        ) ;_ end of function
                      ) ;_ end of vl-catch-all-apply
                ) ;_ end of setq
          ) ;_ end of vl-catch-all-error-p
      (princ (strcat "\n fun_func-2 error : "
                     (vl-catch-all-error-message err)
                     ) ;_ end of strcat
             ) ;_ end of princ
      ) ;_ end of if
    (princ)
    ) ;_ end of defun

  (princ "\ncall (fun_func-2)")
  (fun_func-2)
  (princ "(fun_func-2) finished")

  (if (vl-catch-all-error-p
        (setq err (vl-catch-all-apply
                    (function
                      (lambda ()
                        (princ (vl-princ-to-string (sqrt -1.)))
                        ) ;_ end of lambda
                      ) ;_ end of function
                    ) ;_ end of vl-catch-all-apply
              ) ;_ end of setq
        ) ;_ end of vl-catch-all-error-p
    (princ (strcat "\n lispru-func-1 error : "
                   (vl-catch-all-error-message err)
                   ) ;_ end of strcat
           ) ;_ end of princ
    ) ;_ end of if

  (princ)
  ) ;_ end of defun

Теперь вызов (lispru-func-2) вернет

1
2
3
4
call (fun_func-2)
 fun_func-2 error : divide by zero(fun_func-2) finished
 lispru-func-1 error : function undefined for argument: -1.0
_$

Как видим, выполнение кода не прекращается ни при каких условиях. Что и где применять - в принципе, каждый решает сам, но лично я, проведя в свое время подобные эксперименты, окончательно и бесповоротно отказался от переопределения *error* и перешел на применение vl-catch-* функций.
В примерах я не давал переопределения глобального обработчика ошибок. Желающие поэкспериментировать могут сделать это самостоятельно.

Размещено в Код LISP · Метки:



Комментарии

Есть 2 коммент. к “Код без ошибок – возможно ли?”

Трэкбэки

Узнайте, что другие говорят про эту заметку...
  1. [...] Точно так же можно оперировать не только с переменными, но и с функциями, задавая их область видимости. Подобный подход, например, показывался в Код без ошибок – возможно ли?. [...]

  2. [...] все, что ниже, является продолжением статьи Код без ошибок. Хотелось бы поговорить насчет запроса у пользователя [...]



Поделитесь своим мнением


Я не робот.