В информатике, операция, функция или выражение, как говорят, имеют побочный эффект, если они изменяют какое-либо значение переменной state (s) вне своего локального окружения, то есть имеет наблюдаемый эффект помимо возврата значения (основного эффекта) вызывающей стороне операции. Данные состояния, обновленные «вне» операции, могут поддерживаться «внутри» объекта с отслеживанием состояния или более широкой системы с отслеживанием состояния, в которой выполняется операция. Примеры побочных эффектов включают изменение нелокальной переменной, изменение статической локальной переменной , изменение изменяемого аргумента , переданного по ссылке, выполнение ввода-вывода или вызов других функций побочного эффекта. При наличии побочных эффектов поведение программы может зависеть от истории; то есть порядок оценки имеет значение. Понимание и отладка функции с побочными эффектами требует знания контекста и его возможных историй.
Степень использования побочных эффектов зависит от парадигмы программирования. Императивное программирование обычно используется для создания побочных эффектов, чтобы обновить состояние системы. Напротив, Декларативное программирование обычно используется для сообщения о состоянии системы без побочных эффектов.
В функциональном программировании побочные эффекты используются редко. Отсутствие побочных эффектов упрощает формальную проверку программы. Функциональные языки, такие как Standard ML, Scheme и Scala, не ограничивают побочные эффекты, но программисты обычно их избегают. Функциональный язык Haskell выражает побочные эффекты, такие как ввод-вывод и другие вычисления с сохранением состояния, используя монадические действия.
Программисты на языке ассемблера должны знать скрытых побочных эффектов - инструкции, которые изменяют части состояния процессора, не упомянутые в мнемонике инструкции. Классическим примером скрытого побочного эффекта является арифметическая инструкция, которая неявно изменяет коды условий (скрытый побочный эффект), а также явно изменяет регистр (явный эффект). Одним из потенциальных недостатков набора инструкций со скрытыми побочными эффектами является то, что, если многие инструкции имеют побочные эффекты на одну часть состояния, например коды условий, то логика, необходимая для последовательного обновления этого состояния, может стать производительностью. горлышко бутылки. Проблема особенно остро стоит на некоторых процессорах, разработанных с использованием конвейерной обработки (с 1990 года) или с выполнением вне очереди. Такому процессору может потребоваться дополнительная схема управления для обнаружения скрытых побочных эффектов и остановки конвейера, если следующая инструкция зависит от результатов этих эффектов.
Отсутствие побочных эффектов является необходимым, но не достаточным условием ссылочной прозрачности. Ссылочная прозрачность означает, что выражение (например, вызов функции) может быть заменено его значением. Для этого требуется, чтобы выражение было чистым, то есть выражение должно быть детерминированным (всегда давать одно и то же значение для одного и того же ввода) и побочный эффект свободно.
Побочные эффекты, вызванные временем, затрачиваемым на выполнение операции, обычно игнорируются при обсуждении побочных эффектов и ссылочной прозрачности. В некоторых случаях, например, с аппаратной синхронизацией или тестированием, операции вставляются специально из-за их временных побочных эффектов, например sleep (5000)
или for (int i = 0; i < 10000; ++i) {}
. Эти инструкции не изменяют состояние, за исключением времени для завершения.
Функция f
с побочными эффектами называется идемпотентной при последовательной композиции f; f
, если при двойном вызове с одним и тем же списком аргументов второй вызов имеет без побочных эффектов и возвращает то же значение, что и при первом вызове (при условии, что между концом первого вызова и началом второго вызова не было вызвано никаких других процедур).
Например, рассмотрите следующий Код Python :
x = 0 def setx (n): global xx = n setx (5) setx (5)
Здесь setx
идемпотентен, потому что второй вызов setx
(с тем же аргументом) не изменяет видимое состояние программы: x
уже был установлен на 5 при первом вызове и снова установлен на 5 при втором вызове, таким образом сохраняя то же значение. Обратите внимание, что это отличается от идемпотентности в составе функции f ∘ f
. Например, абсолютное значение идемпотентно в составе функции:
def abs (n): if n < 0: return -n else: return n abs(-5) == abs(abs(-5)) == abs(5) == 5
Одной из распространенных демонстраций поведения побочного эффекта является оператор присваивания в C ++. Например, присвоение возвращает правильный операнд и имеет побочный эффект присвоения этого значения переменной. Это позволяет синтаксически чистое множественное присваивание:
int i, j; я = j = 3;
Поскольку оператор связывает справа, это равняется
int i, j; i = (j = 3); // j = 3 возвращает 3, которое затем присваивается i
, где результат присвоения 3 в j
затем присваивается в i
. Это представляет собой потенциальное зависание для начинающих программистов, которые могут запутать
while (b == 10) {} // проверяет, оценивается ли b как 10
с
while (b = 10) {} // = возвращает 10, который автоматически принимает значение true, поэтому тест всегда выполняется
Термин «побочный эффект» относится к модификации нелокальной среды. Обычно это происходит, когда функция (или процедура) изменяет глобальную переменную или аргументы, передаваемые ссылочными параметрами. Но есть и другие способы изменения нелокальной среды. Мы рассматриваем следующие причины побочных эффектов при вызове функции: 1. Выполнение ввода-вывода. 2. Изменение глобальных переменных. 3. Изменение локальных постоянных переменных (например, статических переменных в C). 4. Изменение аргумента, переданного по ссылке. 5. Изменение локальной переменной (автоматическое или статическое) функции выше в последовательности вызова функции (обычно с помощью указателя).Cite journal требует
| journal =
()