Я чітко не зрозумів поняття побічної дії.
- Що таке побічний ефект у програмуванні?
- Чи залежить від мови програмування?
- Чи існує таке поняття, як зовнішні та внутрішні побічні ефекти?
Наведіть приклад причин, які створюють побічні ефекти.
Я чітко не зрозумів поняття побічної дії.
Наведіть приклад причин, які створюють побічні ефекти.
Відповіді:
Побічним ефектом відноситься просто до модифікації якого - то держави - наприклад:
Всупереч тому, що деякі люди, здається, говорять:
Побічний ефект не повинен бути прихованим чи несподіваним (це може бути, але це не має нічого спільного з визначенням, оскільки це стосується інформатики);
Побічний ефект не має нічого спільного з ідемпотенцією. Ідентифікуюча функція може мати побічні ефекти, а неімпотентна функція може не мати побічних ефектів (наприклад, отримання поточної дати та часу системи).
Це дійсно дуже просто. Побічний ефект = десь щось змінюється.
PS Як зазначає коментатор benjol, кілька людей можуть суперечити визначення побічного ефекту з визначенням чистої функції , що є функцією, яка (а) є безсильною та (b) не має побічних ефектів. Одне не передбачає іншого в загальній інформатиці, але функціональні мови програмування, як правило, мають право виконувати обидва обмеження.
++a
. Не схоже на призначення. b = ++a;
має два побічні ефекти. Очевидна і криптовалюта a
. Це та річ, яка є побічним ефектом, який (для деяких) бажаний. Але мене називали побічним ефектом протягом усієї моєї кар’єри, щоб зробити його не витонченим.
Вважається, що будь-яка операція, яка змінює стан комп'ютера або взаємодіє із зовнішнім світом, має побічний ефект. Дивіться Вікіпедію про побічний ефект .
Наприклад, ця функція не має побічних ефектів. Його результат залежить лише від вхідних аргументів, і нічого про стан програми та її оточення не змінюється, коли вона викликається:
int square(int x) { return x * x; }
На відміну від цього, виклик цих функцій дасть вам різні результати залежно від порядку, в якому ви їх викликаєте, оскільки вони щось змінюють про стан комп'ютера:
int n = 0;
int next_n() { return n++; }
void set_n(int newN) { n = newN; }
Ця функція має побічний ефект запису даних на вихід. Ви не називаєте функцію, оскільки хочете її повернення; ви називаєте це, тому що хочете ефекту, який він має на "зовнішній світ":
int Write(const char* s) { return printf("Output: %s\n", s); }
Write
показує ваш приклад, наявність побічних ефектів не означає, що функція коли-небудь міняє свої виходи відносно вхідних даних або навіть, що її вихід взагалі залежить від вхідних даних.
square(x)
може спричинити завантаження модуля, де функція визначена, з диска. Чи слід це вважати побічним ефектом? Зрештою, ця людина, що (перший) дзвінок несподівано триває, що використання оперативної пам’яті зростає тощо.
square(x)
тому що хочете змінити стан зовнішнього комп'ютера, ви можете вважати це побічним ефектом.
Я вважаю, що наявні відповіді досить хороші. Я хотів би детальніше зупинитися на деяких аспектах, на які ІМО недостатньо підкреслив.
У математиці функція - це просто відображення від набору значень до значення. Таким чином, з огляду на функції f
і значення x
, f(x)
завжди буде той же результат y
. Ви можете також замінити f(x)
з y
усюди в вираженні і нічого не зміниться.
Те, що в багатьох мовах програмування називається функцією (або процедурою), - це конструкція (фрагмент коду), яку можна виконати, оскільки:
Таким чином, ефекти можуть бути пов'язані зі станом, а також з іншими аспектами, такими як вистрілення ракети або призупинення виконання на кілька секунд.
Термін побічний ефект може звучати негативно, але зазвичай ефект виклику функції є самою метою самої функції. Я припускаю, що оскільки термін функція спочатку використовувався в математиці, обчислення значення вважається основним ефектом функції, тоді як будь-які інші ефекти вважаються побічними ефектами . Деякі мови програмування використовують термін процедура, щоб уникнути плутанини з функціями в математичному сенсі.
Зауважте, що
sleep()
в Python, корисні лише для їх (побічних) ефектів,. Вони часто моделюються як функції, які повертають спеціальне значення None
, або unit
або ()
або ..., що просто вказує на те, що обчислення закінчилося правильно.Побічним ефектом є те, коли операція впливає на змінну / об'єкт, що знаходиться поза призначенням.
Це може статися, коли ви здійснюєте виклик складної функції, яка має побічний ефект від зміни якоїсь глобальної змінної, навіть якщо це не було причиною того, що ви її викликали (можливо, ви викликали її, щоб витягти щось із бази даних).
Зізнаюся, у мене виникають проблеми з прикладним простим прикладом, який не виглядає абсолютно надуманим, і приклади з матеріалів, над якими я працював, є занадто довгими для публікації тут (а оскільки це стосується роботи, я, мабуть, не повинен у будь-якому разі ).
Один із прикладів, які я бачив (деякий час тому), - це функція, яка відкрила з'єднання з базою даних, якщо з'єднання було в закритому стані. Проблема полягала в тому, що слід було закрити з'єднання в кінці функції, але розробник забув додати цей код. Отже, тут виникла ненавмисна побічна дія: виклик процедури повинен був робити лише запит, а побічний ефект полягав у тому, що з'єднання залишалося відкритим, і якщо функція викликалася двічі поспіль, виникне помилка, сказавши, що з'єднання було вже відкрито.
Гаразд, тому, оскільки всі наводить приклади зараз, я думаю, що теж буду;)
/*code is PL/SQL-styled pseudo-code because that's what's on my mind right now*/
g_some_global int := 0; --define a globally accessible variable somewhere.
function do_task_x(in_a in number) is
begin
b := calculate_magic(in_a);
if b mod 2 == 0 then
g_some_global := g_some_global + b;
end if;
return (b * 2.3);
end;
Функція do_task_x
має первинний ефект повернення результату деяких обчислень і побічний ефект, можливо, модифікацію глобальної змінної.
Звичайно, що є первинним, а побічним ефектом може бути відкритим для тлумачення і може залежати від фактичного використання. Якщо я називаю цю функцію з метою зміни глобальної і відкидаю повернене значення, ніж я б сказав, що зміна глобального є первинним ефектом.
У інформатиці функція або вираз мають побічний ефект, якщо вони змінюють певний стан або спостерігають взаємодію з функціями виклику або зовнішнім світом.
Функція, в математичному сенсі, - це відображення від введення до виводу. Запропонований ефект виклику функції полягає в тому, щоб вона відображала вхід на вихід, який він повертає. Якщо функція робить щось інше, не має значення, але якщо вона має будь-яку поведінку, яка не відображає вхід на вихід, така поведінка, як відомо, є побічним ефектом.
У більш загальному розумінні побічним ефектом є будь-який ефект, який не є передбачуваним ефектом проектувальника конструкції.
Ефект - це все, що впливає на актора. Якщо я називаю функцію, яка надсилає моїй дівчині розривне текстове повідомлення, яке впливає на купу акторів, мене, її, мережу компанії мобільного телефону тощо. щоб повернути мені карту зі свого введення. Отже для:
public void SendBreakupTextMessage() {
Messaging.send("I'm breaking up with you!")
}
Якщо це призначено для функції, то єдине, що він повинен зробити, це повернути недійсність. Якщо це було побічним ефектом, воно фактично не повинно надсилати текстове повідомлення.
У більшості мов програмування немає побудови для математичної функції. Жодна конструкція не передбачається використовувати як таку. Ось чому більшість мов кажуть, що у вас є методи чи процедури. За задумом вони призначені для досягнення багатьох інших ефектів. У загальній мові програмування ніхто насправді не переймається наміром того, яким був метод чи процедура, тому коли хтось каже, що ця функція має побічну дію, вони фактично означають, що ця конструкція не поводиться як математична функція. І коли хтось каже, що ця функція не має побічних ефектів, це означає, що ця конструкція ефективно поводиться як математична функція.
Чиста функція - це завжди вільний від побічних ефектів визначення. Чиста функція - це спосіб сказати, ця функція, незважаючи на те, що вона використовує конструкцію, яка дозволяє отримати більше ефектів, має лише ефект, рівний такому, який має математична функція.
Я закликаю когось сказати мені, коли функція вільного від побічних ефектів була б не чистою. Якщо первинний призначений ефект контексту речення, що використовує термін чистий та побічний ефект, не є ефектом математичного наміченого ефекту функції, вони завжди рівні.
Як таке, іноді, хоч і рідше, і я вважаю, що цього розходження не вистачає, а також оманливих людей (як це не найпоширеніше припущення) у прийнятій відповіді, але іноді передбачається, що наміченим ефектом функції програмування є для відображення вводу на вихід, де введення не обмежується явними параметрами функції, але вихід обмежується явним значенням повернення. Якщо ви припускаєте, що це призначений ефект, то функція зчитування файлу та повернення іншого результату на основі того, що є у файлі, все ще є вільним від побічних ефектів, оскільки ви дозволяли вводити дані з інших місць у вашому наміченому ефекті.
Отже, чому це все важливо?
Вся справа в контролі та утриманні. Якщо ви викликаєте функцію, і вона робить щось інше, то повертає значення, важко міркувати про її поведінку. Вам потрібно буде заглянути всередину функції для фактичного коду, щоб відгадати, що він робить, і підтвердити його правильність. Ідеальна ситуація полягає в тому, що дуже зрозуміло і легко дізнатися, який саме вхід використовує функція, і що він нічого не робить, то повертаючи вихід для цього. Ви можете трохи розслабитися і сказати, що точно знати, який саме вхід використовується, - це не так корисно, як впевненість, що ви не робите нічого іншого, чого, можливо, не знаєте, потім повертаєте значення, тому, можливо, вас влаштовує лише примусове виконання що він не робить нічого іншого, ніж введення карти, незалежно від того, звідки він отримує, для виведення.
Майже у всіх випадках сенс програми полягає в тому, щоб мати інші ефекти, а не відображення речей, що надходять до речей, що виходять. Ідея контролю побічного ефекту полягає в тому, що ви можете організувати код таким чином, щоб його було легше зрозуміти і міркувати. Якщо ви покладете всі побічні ефекти разом, в дуже чітке і центральне місце, легко дізнатися, де шукати і вірити, що це все, що відбувається, не більше. Якщо ви також маєте дуже чітке введення, це допомагає перевірити поведінку для різних вхідних даних, і це простіше у використанні, оскільки вам не потрібно змінювати вхід у багатьох різних місцях, деякі з яких можуть бути не очевидними, просто щоб отримати те, що ти хочеш.
Оскільки найбільш корисним для розуміння, обґрунтування та контролю поведінки програми є те, щоб весь вхід був чітко згрупований і явний, а також всі побічні ефекти були згруповані разом і явні, про це зазвичай говорять люди, коли говорять побічний ефект, чистий тощо.
Оскільки найбільш корисним є групування побічних ефектів та їх явність, інколи люди це означатимуть лише це, і розрізнити це, кажучи, що це не є чистим, але все-таки "побічним ефектом". Але побічний ефект є відносно припущеного "призначеного первинного ефекту", тому це контекстний термін. Це я знаходжу рідше, хоча дивно, що про це багато говорять.
Нарешті, idempotent означає, що викликати цю функцію багато разів з однаковими входами (неважливо, звідки вони беруться) завжди призведе до однакових ефектів (побічний ефект чи ні).
У програмуванні побічним ефектом є те, коли процедура змінює змінну за межами її області. Побічні ефекти не залежать від мови. Є деякі класи мов, які спрямовані на усунення побічних ефектів (чисто функціональні мови), але я не впевнений, чи є такі, які потребують побічних ефектів, але я можу помилитися.
Наскільки мені відомо, немає внутрішніх і зовнішніх побічних ефектів.
Ось простий приклад:
int _totalWrites;
void Write(string message)
{
// Invoking this function has the side effect of
// incrementing the value of _totalWrites.
_totalWrites++;
Debug.Write(message);
}
Визначення побічного ефекту не характерне для програмування, тому просто уявіть собі побічні ефекти ліків або вживання занадто багато їжі.
x++
модифікує змінну x
, зазвичай вважається побічним ефектом. Це значення виразу є попереднім збільшенням x
; це частина виразу без побічних ефектів.
Побічний ефект - це речі, які трапляються в коді, які явно не очевидні.
Наприклад, скажімо, у вас цей клас
public class ContrivedRandomGenerator {
public int Seed { get; set; }
public int GetRandomValue()
{
Random(Seed);
Seed++;
}
}
Коли ви спочатку створюєте клас, ви даєте йому насіння.
var randomGenerator = new ContrivedRandomGenerator();
randomGenerator.Seed = 15;
randomGenerator.GetRandomValue();
Ви не знаєте внутрішніх справ, ви просто розраховуєте отримати випадкову величину, і ви очікуєте, що randomGenerator.Потрібно все-таки бути 15 ... але це не так.
Виклик функції мав побічний ефект від зміни значення Seed.