Охрана (программирование)
Охрана в программировании — это булево выражение, которое должно быть истинным, чтобы выполнение программы продолжилось по соответствующей ветви. Независимо от используемого языка программирования, охраняющее выражение, охраняющий код или охраняющее утверждение — это проверка предусловий целостности, используемая для предотвращения ошибок во время выполнения.
Термин охраняющее утверждение является шаблоном проектирования программного обеспечения, приписываемым Кенту Беку, который формализовал многие ранее безымянные практики программирования в виде именованных шаблонов. Однако практика использования этого приёма восходит как минимум к началу 1960-х годов. Охраняющее утверждение чаще всего добавляется в начале процедуры и «охраняет» остальной код, обрабатывая граничные случаи заранее.
Использование
Типичный пример — проверка того, что ссылка, которая будет обработана, не равна null, что предотвращает ошибки нулевого указателя.
Другие применения включают использование булева поля для идемпотентности (чтобы последующие вызовы были NOP), как, например, в шаблоне освобождения ресурсов.
public String foo(String username) {
if (username == null) {
throw new IllegalArgumentException("Username is null.");
}
// Остальной код метода...
}
Охрана обеспечивает ранний выход из подпрограммы и является распространённым отклонением от структурного программирования, устраняя один уровень вложенности и делая код более плоским:[1] заменяя if guard { ... } на if not guard: return; ....
Использование охраняющих утверждений может быть техникой рефакторинга для улучшения кода. В целом, меньшая вложенность упрощает код и снижает когнитивную нагрузку.
Например, на Python:
from typing import Any, Optional
# Эта функция не использует охраняющее утверждение
def f_noguard(x: Any) -> Optional[int]:
if isinstance(x, int):
# код здесь
return x + 1
else:
return None
# Эквивалентная функция с охраняющим утверждением. Обратите внимание, что большая часть кода менее вложена, что облегчает чтение и понимание
def f_guard(x: Any) -> Optional[int]:
if not isinstance(x, int):
return None
# код здесь
return x + 1
Другой пример на C:
// Эта функция не использует охраняющее утверждение
int funcNoGuard(int x) {
if (x >= 0) {
// код здесь
return x + 1;
} else {
return 0;
}
}
// Эквивалентная функция с охраняющим утверждением
int funcGuard(int x) {
if (x < 0) {
return 0;
}
// код здесь
return x + 1;
}
Терминология
Термин используется в специфическом значении в языках APL, Haskell, Clean, Erlang, occam, Promela, OCaml, Swift[2], Python начиная с версии 3.10, и Scala.Citation needed В Mathematica охраны называются ограничениями (constraints). Охраны — фундаментальное понятие в , используемом в формальных методах. Охраны могут использоваться для расширения сопоставления с образцом с возможностью пропуска образца, даже если структура совпадает. Булевы выражения в условных операторах обычно также соответствуют этому определению охраны, хотя чаще называются условиями.
Математика
В следующем примере на Haskell охраны располагаются между каждой парой символов "|" и "=":
f x
| x > 0 = 1
| otherwise = 0
Это похоже на соответствующую математическую запись:
В данном случае охраны находятся в частях "если" и "иначе".
Несколько охран
Если имеется несколько параллельных охран, они обычно проверяются сверху вниз, и выбирается ветвь первой прошедшей охраны. Охраны в списке случаев, как правило, параллельны.
Однако в Haskell при списковых включениях охраны идут последовательно, и если хотя бы одна из них не выполняется, элемент списка не создаётся. Это эквивалентно объединению отдельных охран с помощью логического И, за исключением того, что между охранами могут быть и другие части выражения спискового включения.
Эволюция
Простое условное выражение, уже присутствовавшее в CPL в 1963 году, содержит охрану в первой подвыражении и другое подвыражение, используемое, если первое не может быть применено. Некоторые распространённые способы записи:
(x>0) -> 1/x; 0 x>0 ? 1/x : 0
Если второе подвыражение также может быть простым условным выражением, можно задать больше альтернатив до последнего fall-through:
(x>0) -> 1/x; (x<0) -> -1/x; 0
В 1966 году ISWIM имел форму условного выражения без обязательного случая по умолчанию, тем самым отделяя охрану от выбора между альтернативами. В случае ISWIM, если ни одна альтернатива не могла быть использована, значение считалось неопределённым, что означало невозможность вычисления значения.
KRC, «миниатюрная версия»[3] SASL (1976), был одним из первых языков программирования, использовавших термин «охрана». Его определения функций могли содержать несколько предложений, и выбиралось то, для которого выполнялась охрана, следующая за предложением:
fac n = 1, n = 0
= n * fac (n-1), n > 0
Использование охраняющих утверждений и сам термин «охраняющее утверждение» восходят как минимум к практике Smalltalk 1990-х годов, формализованной Кентом Беком[1].
В 1996 году Dyalog APL принял альтернативный чисто функциональный стиль, в котором охрана является единственной управляющей структурой[4]. Пример на APL, вычисляющий чётность числа:
parity←{
2∣⍵ : 'odd'
'even'
}
Охрана с образцом
В дополнение к охране, связанной с образцом, охрана с образцом может означать использование сопоставления с образцом в контексте охраны. По сути, совпадение с образцом считается прохождением охраны. Это значение было введено в предложении для Haskell Саймоном Пейтоном Джонсом под названием A new view of guards в апреле 1997 года и было реализовано в языке. Эта возможность позволяет использовать образцы в охранах образца.
Пример на расширенном Haskell:
clunky env var1 var2
| Just val1 <- lookup env var1
, Just val2 <- lookup env var2
= val1 + val2
-- ...другие уравнения для clunky...
Это читается так: «clunky для окружения и двух переменных, если поиск переменных в окружении возвращает значения, равен сумме этих значений...». Как и в списковых включениях, охраны идут последовательно, и если хотя бы одна из них не выполняется, ветвь не выбирается.
См. также
Примечания
Ссылки
- Охрана в Free On-Line Dictionary of Computing — FOLDOC, Денис Хау (ред.).
- Охраняющее утверждение, WikiWikiWeb
- The Haskell 98 Report, глава 3. Выражения.
- The Mathematica Book, раздел 2.3.5 Ограничения на образцы
- The Glorious Glasgow Haskell Compilation System User's Guide, версия 6.4, раздел 7.3.2. Охраны с образцом


