Побічний ефект (програмування)
Функція або вираз мають побічний ефект, якщо, на додаток до повернення значення, вони змінюють якийсь стан програми або проводять видиму взаємодію з викликальною функцією або зовнішнім світом. Наприклад, функція може змінювати глобальну або статичну змінну, змінювати один зі своїх аргументів, спричиняти виняткову ситуацію, виводити дані на пристрій виведення або у файл, читати дані або викликати інші функції з побічними ефектами. За наявності побічних ефектів, поведінка програми залежить від історії; тобто порядок обчислень має значення. Розуміння програми з побічними ефектами вимагає знання про контекст та історію; навіть при наявності цих знань важко добрати перебіг програми, а також зневадити її.[1][2]
Побічні ефекти — найзвичніший спосіб взаємодії з зовнішнім світом (людьми, файловою системою, іншими комп'ютерами в мережі). Ступінь використання побічних ефектів залежить від парадигми програмування. Імперативне програмування відоме частим використанням побічних ефектів. У функціональному програмуванні побічні ефекти використовують зрідка. Функціональні мови такі як Standard ML або Scheme не забороняють побічні ефекти, але зазвичай програмісти уникають їх.[3] Функціональна мова Haskell обмежує побічні ефекти через статичну систему типізації; вона використовує концепцію монад.[4][5]
Розробники на мові асемблера мають зважати на приховані побічні ефекти — інструкції, які змінюють частину стану процесора без зазначення цього в своїх назвах. Класичний приклад прихованого побічного ефекту — арифметична інструкція, яка явно змінює регістр (явний ефект (англ. overt effect)) і неявно змінює коди умов (прихований побічний ефект). Наприклад, прапорці, що вказують на те, що в результаті отримано нуль або переповнення. Один з недоліків набору інструкцій з багатьма побічними ефектами полягає в можливості впливу на одну частинку стану, наприклад коди умов, тоді коли вимога оновлювати ці стани послідовно може стати вузьким місцем швидкодії. Проблема постає особливо гостро на процесорах розроблених з конвеєром команд (з 1990) або з позачерговим виконанням. Такі процесори можуть потребувати додаткову схему для перевірки на побічні ефекти і зупиняти конвеєр, якщо наступна інструкція залежить від наслідків цих ефектів.
Прозорість посилань
Відсутність побічних ефектів є необхідною, але не достатньою умовою для прозорості посилань. Прозорість посилань значить, що вираз (такий як виклик функції) може бути заміненим на його значення; для цього необхідно, щоб вираз не тільки не мав побічних ефектів, але й був чистим (завжди повертав той самий результат для одних вхідних даних).
Часові побічні ефекти
На побічні ефекти, пов'язані з часом необхідним для виконання дії, зазвичай не зважають, коли йдеться про побічні ефекти або прозорість посилань. В більшості програм бажано замінювати довгі дії на коротші, наприклад, (60 / 3 * 2)
на 40
. Іноді, коли йдеться про синхронізацію або тестування, зумисне вставляються такі коди, що мають часовий побічний ефект, наприклад, Sleep(5000)
або for(i=0; i < 10000; i++){}
. Ці інструкції не змінюють стан окрім потреби очікування до їх завершення.
Ідемпотентність
Функція без побічних ефектів f завжди ідемпотентна (в розумінні послідовних викликів f; f, але не композиції функцій f ∘ f).
Примітки
- «Research Topics in Functional Programming» ed. D. Turner, Addison-Wesley, 1990, pp 17–42. Retrieved from: Hughes, John. Why Functional Programming Matters (PDF).
- Collberg. CSc 520 Principles of Programming Languages. Department of Computer Science, University of Arizona.
- Matthias Felleisen. How To Design Programs. MIT Press.
- Haskell 98 Library Report: Input/Output.
- Imperative Functional Programming, Simon Peyton Jones and Phil Wadler, Conference Record of the 20th Annual ACM Symposium on Principles of Programming Languages, pages 71–84, 1993