Ошибка

Ошибка — недостаток программы, проявляющийся в том, что она работает не так, как задумал программист или как ожидают пользователи. То же: error.

Все ошибки можно разделить (условно) на 4 типа:

Ошибки времени компиляции

Это те ошибки, которые ловит компилятор и которые, таким образом, нарушают некоторые важные для компилятора принципы. Типичный пример — синтаксическая ошибка.

$ echo '-mmodule(hello).' > hello.erl && erlc hello.erl 
hello.erl:1:2: no module definition
%    1| -mmodule(hello).
%     |  ^

Логические ошибки

Это ошибки, вызванные плохо проработанной моделью происходящего в программе. В частности, плохой организацией архитектуры программы или игнорированием всех возможных случаев. Некоторые логические ошибки бывают очень тонкими и можно буквально часами не понимать, почему ты нажимаешь на кнопку, а ожидаемый эффект не наступает.

Часто логические ошибки бывают просто следствием невнимательности программиста. Допустим, он разрабатывает игру, в которой выбрасываются два игральных кубика и в зависимости от суммы на кубиках наступает то или иное игровое действие. Программисту может показаться, что сумма будет в диапазоне от 1 до 12, и к числу 1 он привяжет какое-либо действие. Это действие, конечно, никогда не наступит. Скорее всего, программист рано или поздно заметит такую ошибку (по тому, что какое-то событие в принципе не наступает).

Но может быть и более тонкая, смысловая ошибка, связанная с тем, что программист не владеет даже азами комбинаторики и теории вероятности. Он, например, может подумать (продолжаем пример с кубиками), что все числа от 2 до 12 выпадают с одинаковой вероятностью. Это, конечно, не так, но бот в игре будет опираться на эту модель и поэтому будет систематически ошибаться.

Игральные кубики

Могут быть и другого рода “научные ошибки”, вызванные, например, непониманием математической статистики, законов физики, юридических законов — вплоть до орфографических ошибок. Некоторые такие ошибки наглядны и легко выявляются — следует лишь дождаться обратной связи от пользователей.

Но некоторые логические ошибки очень сложно отлавливать. Поэтому лучше сразу опираться на стройную, хорошо продуманную модель происходящего в программе и не ждать, что ошибки потом себя всё равно проявят.

Ошибки времени исполнения

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

1> odin = 1. 
** exception error: no match of right hand side value 1
2> 5 / 0. 
** exception error: an error occurred when evaluating
    an arithmetic expression
     in operator  '/'/2
        called as 5 / 0

То, что программа столкнулась с исключительной ситуацией (“споткнулась”), не значит, что всё пропало, что теперь программу надо запускать заново. Во-первых, мы можем поддержать нашу программу тем, что заранее предусмотрительно выдадим ей “костыли” в виде обработки исключений. Во-вторых, раз мы программируем на Эрланге, у нас может быть много-много разных акторов, и то, что в одном из них вдруг возникла проблема, совсем не повод для того, чтобы ронять всю Систему.

Джо Армстронг написал и защитил диссертацию под названием “Создание надёжных распределённых систем при наличии программных ошибок”. Один из тезисов, который он в ней отстаивает, — для создания надёжной системы не надо обрабатывать ошибки локально. Надо дать актору рухнуть, а потом уже — в зависимости от ситуации — что-то уже делать с этим.

Ошибки времени исполнения возникают с надписью: exception error: .... Если мы желаем сами смоделировать такого рода ошибку — с произвольной причиной, — то можем вызвать error(Причина).

5> error("Too many candies"). 
** exception error: "Too many candies"

Генерируемые ошибки

Те, которые вызываются преднамеренно. Если программист опасается, что что-то может пойти не так, он может добавить в код вызов throw/1 или exit/1.

1> throw("Bad"). 
** exception throw: "Bad"
2> exit("Very bad"). 
** exception exit: "Very bad"

Как мы видим, в одном случае в оболочке возникает сообщение exception throw..., а в другом случае — exception exit....


© Алексей Карманов, 2024.